aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorXavier Leroy <xavier.leroy@inria.fr>2019-08-08 11:18:38 +0200
committerXavier Leroy <xavier.leroy@college-de-france.fr>2019-08-08 11:18:38 +0200
commit7cdd676d002e33015b496f609538a9e86d77c543 (patch)
treef4d105bce152445334613e857d4a672976a56f3e
parenteb85803875c5a4e90be60d870f01fac380ca18b0 (diff)
downloadcompcert-7cdd676d002e33015b496f609538a9e86d77c543.tar.gz
compcert-7cdd676d002e33015b496f609538a9e86d77c543.zip
AArch64 port
This commit adds a back-end for the AArch64 architecture, namely ARMv8 in 64-bit mode.
-rw-r--r--.gitignore3
-rw-r--r--aarch64/Archi.v88
-rw-r--r--aarch64/Asm.v1312
-rw-r--r--aarch64/AsmToJSON.ml24
-rw-r--r--aarch64/Asmexpand.ml436
-rw-r--r--aarch64/Asmgen.v1151
-rw-r--r--aarch64/Asmgenproof.v1026
-rw-r--r--aarch64/Asmgenproof1.v1836
-rw-r--r--aarch64/Builtins1.v33
-rw-r--r--aarch64/CBuiltins.ml72
-rw-r--r--aarch64/CombineOp.v137
-rw-r--r--aarch64/CombineOpproof.v161
-rw-r--r--aarch64/ConstpropOp.vp401
-rw-r--r--aarch64/ConstpropOpproof.v838
-rw-r--r--aarch64/Conventions1.v380
-rw-r--r--aarch64/Machregs.v210
-rw-r--r--aarch64/Machregsaux.ml35
-rw-r--r--aarch64/NeedOp.v253
-rw-r--r--aarch64/Op.v1778
-rw-r--r--aarch64/PrintOp.ml247
-rw-r--r--aarch64/SelectLong.vp478
-rw-r--r--aarch64/SelectLongproof.v764
-rw-r--r--aarch64/SelectOp.vp566
-rw-r--r--aarch64/SelectOpproof.v1070
-rw-r--r--aarch64/Stacklayout.v140
-rw-r--r--aarch64/TargetPrinter.ml592
-rw-r--r--aarch64/ValueAOp.v319
-rw-r--r--aarch64/extractionMachdep.v23
-rw-r--r--backend/Asmgenproof0.v51
-rw-r--r--backend/Lineartyping.v2
-rw-r--r--backend/NeedDomain.v24
-rw-r--r--backend/SelectDivproof.v20
-rw-r--r--backend/Selectionaux.ml2
-rw-r--r--backend/Selectionproof.v4
-rw-r--r--backend/ValueDomain.v31
-rwxr-xr-xconfigure38
-rw-r--r--cparser/Machine.ml5
-rw-r--r--cparser/Machine.mli1
-rw-r--r--driver/Configuration.ml2
-rw-r--r--driver/Frontend.ml1
-rw-r--r--lib/Integers.v160
-rw-r--r--riscV/Asmgenproof1.v16
-rw-r--r--runtime/Makefile2
-rw-r--r--runtime/aarch64/sysdeps.h45
-rw-r--r--runtime/aarch64/vararg.S109
-rw-r--r--test/regression/Results/builtins-aarch6415
-rw-r--r--test/regression/builtins-aarch64.c47
-rw-r--r--test/regression/extasm.c13
48 files changed, 14874 insertions, 87 deletions
diff --git a/.gitignore b/.gitignore
index f33b2173..4b497387 100644
--- a/.gitignore
+++ b/.gitignore
@@ -40,6 +40,9 @@
/riscV/ConstpropOp.v
/riscV/SelectOp.v
/riscV/SelectLong.v
+/aarch64/ConstpropOp.v
+/aarch64/SelectOp.v
+/aarch64/SelectLong.v
/backend/SelectDiv.v
/backend/SplitLong.v
/cparser/Parser.v
diff --git a/aarch64/Archi.v b/aarch64/Archi.v
new file mode 100644
index 00000000..aef4ab77
--- /dev/null
+++ b/aarch64/Archi.v
@@ -0,0 +1,88 @@
+(* *********************************************************************)
+(* *)
+(* 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. *)
+(* *)
+(* *********************************************************************)
+
+(** Architecture-dependent parameters for AArch64 *)
+
+Require Import ZArith List.
+(*From Flocq*)
+Require Import Binary Bits.
+
+Definition ptr64 := true.
+
+Definition big_endian := false.
+
+Definition align_int64 := 8%Z.
+Definition align_float64 := 8%Z.
+
+Definition splitlong := false.
+
+Lemma splitlong_ptr32: splitlong = true -> ptr64 = false.
+Proof.
+ unfold splitlong, ptr64; congruence.
+Qed.
+
+Definition default_nan_64 := (false, iter_nat 51 _ xO xH).
+Definition default_nan_32 := (false, iter_nat 22 _ xO xH).
+
+(** Choose the first signaling NaN, if any;
+ otherwise choose the first NaN;
+ otherwise use default. *)
+
+Definition choose_nan (is_signaling: positive -> bool)
+ (default: bool * positive)
+ (l0: list (bool * positive)) : bool * positive :=
+ let fix choose_snan (l1: list (bool * positive)) :=
+ match l1 with
+ | nil =>
+ match l0 with nil => default | n :: _ => n end
+ | ((s, p) as n) :: l1 =>
+ if is_signaling p then n else choose_snan l1
+ end
+ in choose_snan l0.
+
+Lemma choose_nan_idem: forall is_signaling default n,
+ choose_nan is_signaling default (n :: n :: nil) =
+ choose_nan is_signaling default (n :: nil).
+Proof.
+ intros. destruct n as [s p]; unfold choose_nan; simpl.
+ destruct (is_signaling p); auto.
+Qed.
+
+Definition choose_nan_64 :=
+ choose_nan (fun p => negb (Pos.testbit p 51)) default_nan_64.
+
+Definition choose_nan_32 :=
+ choose_nan (fun p => negb (Pos.testbit p 22)) default_nan_32.
+
+Lemma choose_nan_64_idem: forall n,
+ choose_nan_64 (n :: n :: nil) = choose_nan_64 (n :: nil).
+Proof. intros; apply choose_nan_idem. Qed.
+
+Lemma choose_nan_32_idem: forall n,
+ choose_nan_32 (n :: n :: nil) = choose_nan_32 (n :: nil).
+Proof. intros; apply choose_nan_idem. Qed.
+
+Definition fma_order {A: Type} (x y z: A) := (z, x, y).
+
+Definition fma_invalid_mul_is_nan := true.
+
+Definition float_of_single_preserves_sNaN := false.
+
+Global Opaque ptr64 big_endian splitlong
+ default_nan_64 choose_nan_64
+ default_nan_32 choose_nan_32
+ fma_order fma_invalid_mul_is_nan
+ float_of_single_preserves_sNaN.
+
+(** Whether to generate position-independent code or not *)
+
+Parameter pic_code: unit -> bool.
diff --git a/aarch64/Asm.v b/aarch64/Asm.v
new file mode 100644
index 00000000..47cd3051
--- /dev/null
+++ b/aarch64/Asm.v
@@ -0,0 +1,1312 @@
+(* *********************************************************************)
+(* *)
+(* 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. *)
+(* *)
+(* *********************************************************************)
+
+(** 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.
+
+(** * Abstract syntax *)
+
+(** Integer registers, floating-point registers. *)
+
+(** In assembly files, [Xn] denotes the full 64-bit register
+ and [Wn] the low 32 bits of [Xn]. *)
+
+Inductive ireg: Type :=
+ | X0 | X1 | X2 | X3 | X4 | X5 | X6 | X7
+ | X8 | X9 | X10 | X11 | X12 | X13 | X14 | X15
+ | X16 | X17 | X18 | X19 | X20 | X21 | X22 | X23
+ | X24 | X25 | X26 | X27 | X28 | X29 | X30.
+
+Inductive ireg0: Type :=
+ | RR0 (r: ireg) | XZR.
+
+Inductive iregsp: Type :=
+ | RR1 (r: ireg) | XSP.
+
+Coercion RR0: ireg >-> ireg0.
+Coercion RR1: ireg >-> iregsp.
+
+Lemma ireg_eq: forall (x y: ireg), {x=y} + {x<>y}.
+Proof. decide equality. Defined.
+
+(** In assembly files, [Dn] denotes the low 64-bit of a vector register,
+ and [Sn] the low 32 bits. *)
+
+Inductive freg: Type :=
+ | D0 | D1 | D2 | D3 | D4 | D5 | D6 | D7
+ | D8 | D9 | D10 | D11 | D12 | D13 | D14 | D15
+ | D16 | D17 | D18 | D19 | D20 | D21 | D22 | D23
+ | D24 | D25 | D26 | D27 | D28 | D29 | D30 | D31.
+
+Lemma freg_eq: forall (x y: freg), {x=y} + {x<>y}.
+Proof. decide equality. Defined.
+
+(** Bits in the condition register. *)
+
+Inductive crbit: Type :=
+ | CN: crbit (**r negative *)
+ | CZ: crbit (**r zero *)
+ | CC: crbit (**r carry *)
+ | CV: crbit. (**r overflow *)
+
+Lemma crbit_eq: forall (x y: crbit), {x=y} + {x<>y}.
+Proof. decide equality. Defined.
+
+(** 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.
+Coercion CR: crbit >-> preg.
+
+Lemma preg_eq: forall (x y: preg), {x=y} + {x<>y}.
+Proof. decide equality. apply ireg_eq. apply freg_eq. apply crbit_eq. Defined.
+
+Module PregEq.
+ Definition t := preg.
+ Definition eq := preg_eq.
+End PregEq.
+
+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.
+
+(** The instruction set. Most instructions correspond exactly to
+ actual AArch64 instructions. See the ARM reference manuals for more
+ details. Some instructions, described below, are
+ pseudo-instructions: they expand to canned instruction sequences
+ during the printing of the assembly code. *)
+
+Definition label := positive.
+
+Inductive isize: Type :=
+ | W (**r 32-bit integer operation *)
+ | X. (**r 64-bit integer operation *)
+
+Inductive fsize: Type :=
+ | S (**r 32-bit, single-precision FP operation *)
+ | D. (**r 64-bit, double-precision FP operation *)
+
+Inductive testcond : Type :=
+ | TCeq: testcond (**r equal *)
+ | TCne: testcond (**r not equal *)
+ | TChs: testcond (**r unsigned higher or same *)
+ | TClo: testcond (**r unsigned lower *)
+ | TCmi: testcond (**r negative *)
+ | TCpl: testcond (**r positive *)
+ | TChi: testcond (**r unsigned higher *)
+ | TCls: testcond (**r unsigned lower or same *)
+ | TCge: testcond (**r signed greater or equal *)
+ | TClt: testcond (**r signed less than *)
+ | TCgt: testcond (**r signed greater *)
+ | TCle: testcond. (**r signed less than or equal *)
+
+Inductive addressing: Type :=
+ | ADimm (base: iregsp) (n: int64) (**r base plus immediate offset *)
+ | ADreg (base: iregsp) (r: ireg) (**r base plus reg *)
+ | ADlsl (base: iregsp) (r: ireg) (n: int) (**r base plus reg LSL n *)
+ | ADsxt (base: iregsp) (r: ireg) (n: int) (**r base plus SIGN-EXT(reg) LSL n *)
+ | ADuxt (base: iregsp) (r: ireg) (n: int) (**r base plus ZERO-EXT(reg) LSL n *)
+ | ADadr (base: iregsp) (id: ident) (ofs: ptrofs) (**r base plus low address of [id + ofs] *)
+ | ADpostincr (base: iregsp) (n: int64). (**r base plus offset; base is updated after *)
+
+Inductive shift_op: Type :=
+ | SOnone
+ | SOlsl (n: int)
+ | SOlsr (n: int)
+ | SOasr (n: int)
+ | SOror (n: int).
+
+Inductive extend_op: Type :=
+ | EOsxtb (n: int)
+ | EOsxth (n: int)
+ | EOsxtw (n: int)
+ | EOuxtb (n: int)
+ | EOuxth (n: int)
+ | EOuxtw (n: int)
+ | EOuxtx (n: int).
+
+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 *)
+.
+
+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.
+
+(** * 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
+ type [Tint], float registers to values of type [Tfloat],
+ 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.
+
+(** 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.
+
+Open Scope asm.
+
+(** Undefining some registers *)
+
+Fixpoint undef_regs (l: list preg) (rs: regset) : regset :=
+ match l with
+ | nil => rs
+ | r :: l' => undef_regs l' (rs#r <- Vundef)
+ end.
+
+(** Undefining the condition codes *)
+
+Definition undef_flags (rs: regset) : regset :=
+ fun r => match r with CR _ => Vundef | _ => rs r end.
+
+(** Assigning a register pair *)
+
+Definition set_pair (p: rpair preg) (v: val) (rs: regset) : regset :=
+ match p with
+ | One r => rs#r <- v
+ | Twolong rhi rlo => rs#rhi <- (Val.hiword v) #rlo <- (Val.loword v)
+ end.
+
+(** Assigning the result of a builtin *)
+
+Fixpoint set_res (res: builtin_res preg) (v: val) (rs: regset) : regset :=
+ match res with
+ | BR r => rs#r <- v
+ | BR_none => rs
+ | 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.
+
+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.
+
+Section RELSEM.
+
+Variable ge: genv.
+
+(** 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 + 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. *)
+
+Inductive outcome: Type :=
+ | Next: regset -> mem -> outcome
+ | Stuck: outcome.
+
+(** Manipulations over the [PC] register: continuing with the next
+ instruction ([nextinstr]) or branching to a label ([goto_label]). *)
+
+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.
+
+(** Testing a condition *)
+
+Definition eval_testcond (c: testcond) (rs: regset) : option bool :=
+ match c with
+ | TCeq => (**r equal *)
+ match rs#CZ with
+ | Vint n => Some (Int.eq n Int.one)
+ | _ => None
+ end
+ | TCne => (**r not equal *)
+ match rs#CZ with
+ | Vint n => Some (Int.eq n Int.zero)
+ | _ => None
+ end
+ | TClo => (**r unsigned less than *)
+ match rs#CC with
+ | Vint n => Some (Int.eq n Int.zero)
+ | _ => None
+ end
+ | TCls => (**r unsigned less or equal *)
+ match rs#CC, rs#CZ 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 rs#CC with
+ | Vint n => Some (Int.eq n Int.one)
+ | _ => None
+ end
+ | TChi => (**r unsigned greater *)
+ match rs#CC, rs#CZ with
+ | Vint c, Vint z => Some (Int.eq c Int.one && Int.eq z Int.zero)
+ | _, _ => None
+ end
+ | TClt => (**r signed less than *)
+ match rs#CV, rs#CN with
+ | Vint o, Vint s => Some (Int.eq (Int.xor o s) Int.one)
+ | _, _ => None
+ end
+ | TCle => (**r signed less or equal *)
+ match rs#CV, rs#CN, rs#CZ 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 rs#CV, rs#CN with
+ | Vint o, Vint s => Some (Int.eq (Int.xor o s) Int.zero)
+ | _, _ => None
+ end
+ | TCgt => (**r signed greater *)
+ match rs#CV, rs#CN, rs#CZ 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 rs#CN with
+ | Vint n => Some (Int.eq n Int.zero)
+ | _ => None
+ end
+ | TCmi => (**r negative *)
+ match rs#CN with
+ | Vint n => Some (Int.eq n Int.one)
+ | _ => None
+ end
+ end.
+
+(** Integer "is zero?" test *)
+
+Definition eval_testzero (sz: isize) (v: val) (m: mem): 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)
+ end.
+
+(** Integer "bit is set?" test *)
+
+Definition eval_testbit (sz: isize) (v: val) (n: int): option bool :=
+ match sz with
+ | W => Val.cmp_bool Cne (Val.and v (Vint (Int.shl Int.one n))) (Vint Int.zero)
+ | 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) :=
+ 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)
+ #CV <- (Val.sub_overflow v1 v2).
+
+Definition compare_long (rs: regset) (v1 v2: val) (m: mem) :=
+ 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))
+ #CV <- (Val.subl_overflow v1 v2).
+
+(** Semantics of [fcmp] instructions:
+<<
+== N=0 Z=1 C=1 V=0
+< N=1 Z=0 C=0 V=0
+> N=0 Z=0 C=1 V=0
+unord N=0 Z=0 C=1 V=1
+>>
+*)
+
+Definition compare_float (rs: regset) (v1 v2: val) :=
+ match v1, v2 with
+ | Vfloat f1, Vfloat f2 =>
+ rs#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)))
+ | _, _ =>
+ rs#CN <- Vundef
+ #CZ <- Vundef
+ #CC <- Vundef
+ #CV <- Vundef
+ end.
+
+Definition compare_single (rs: regset) (v1 v2: val) :=
+ match v1, v2 with
+ | Vsingle f1, Vsingle f2 =>
+ rs#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)))
+ | _, _ =>
+ rs#CN <- Vundef
+ #CZ <- Vundef
+ #CC <- Vundef
+ #CV <- Vundef
+ end.
+
+(** Insertion of bits into an integer *)
+
+Definition insert_in_int (x: val) (y: Z) (pos: Z) (len: Z) : val :=
+ match x with
+ | Vint n => Vint (Int.repr (Zinsert (Int.unsigned n) y pos len))
+ | _ => Vundef
+ end.
+
+Definition insert_in_long (x: val) (y: Z) (pos: Z) (len: Z) : val :=
+ match x with
+ | Vlong n => Vlong (Int64.repr (Zinsert (Int64.unsigned n) y pos len))
+ | _ => Vundef
+ end.
+
+(** Evaluation of shifted operands *)
+
+Definition eval_shift_op_int (v: val) (s: shift_op): val :=
+ match s with
+ | SOnone => v
+ | SOlsl n => Val.shl v (Vint n)
+ | SOlsr n => Val.shru v (Vint n)
+ | SOasr n => Val.shr v (Vint n)
+ | SOror n => Val.ror v (Vint n)
+ end.
+
+Definition eval_shift_op_long (v: val) (s: shift_op): val :=
+ match s with
+ | SOnone => v
+ | SOlsl n => Val.shll v (Vint n)
+ | SOlsr n => Val.shrlu v (Vint n)
+ | SOasr n => Val.shrl v (Vint n)
+ | SOror n => Val.rorl v (Vint n)
+ end.
+
+(** Evaluation of sign- or zero- extended operands *)
+
+Definition eval_extend (v: val) (x: extend_op): val :=
+ match x with
+ | EOsxtb n => Val.shll (Val.longofint (Val.sign_ext 8 v)) (Vint n)
+ | EOsxth n => Val.shll (Val.longofint (Val.sign_ext 16 v)) (Vint n)
+ | EOsxtw n => Val.shll (Val.longofint v) (Vint n)
+ | EOuxtb n => Val.shll (Val.longofintu (Val.zero_ext 8 v)) (Vint n)
+ | EOuxth n => Val.shll (Val.longofintu (Val.zero_ext 16 v)) (Vint n)
+ | EOuxtw n => Val.shll (Val.longofintu v) (Vint n)
+ | EOuxtx n => Val.shll v (Vint n)
+ end.
+
+(** Bit-level conversion from integers to FP numbers *)
+
+Definition float32_of_bits (v: val): val :=
+ match v with
+ | Vint n => Vsingle (Float32.of_bits n)
+ | _ => Vundef
+ end.
+
+Definition float64_of_bits (v: val): val :=
+ match v with
+ | Vlong n => Vfloat (Float.of_bits n)
+ | _ => 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.
+*)
+
+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 eval_testcond 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.
+
+(** 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',
+ rs PC = Vptr b ofs ->
+ Genv.find_funct_ptr ge b = Some (Internal f) ->
+ find_instr (Ptrofs.unsigned ofs) f.(fn_code) = Some i ->
+ exec_instr f i rs m = Next rs' m' ->
+ step (State rs m) E0 (State rs' m')
+ | exec_step_builtin:
+ forall b ofs f ef args res rs m vargs t vres 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 (Pbuiltin ef args res) ->
+ eval_builtin_args ge rs rs#SP m args vargs ->
+ external_call ef ge vargs m t vres m' ->
+ rs' = nextinstr
+ (set_res res vres
+ (undef_regs (map preg_of (destroyed_by_builtin ef)) rs)) ->
+ 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 (p: program) :=
+ Semantics step (initial_state p) final_state (Genv.globalenv p).
+
+(** Determinacy of the [Asm] semantics. *)
+
+Remark extcall_arguments_determ:
+ forall rs m sg args1 args2,
+ extcall_arguments rs m sg args1 -> extcall_arguments rs m sg args2 -> args1 = args2.
+Proof.
+ intros until m.
+ assert (A: forall l v1 v2,
+ extcall_arg rs m l v1 -> extcall_arg rs m l v2 -> v1 = v2).
+ { intros. inv H; inv H0; congruence. }
+ assert (B: forall p v1 v2,
+ extcall_arg_pair rs m p v1 -> extcall_arg_pair rs m p v2 -> v1 = v2).
+ { intros. inv H; inv H0.
+ eapply A; eauto.
+ f_equal; eapply A; eauto. }
+ assert (C: forall ll vl1, list_forall2 (extcall_arg_pair rs m) ll vl1 ->
+ forall vl2, list_forall2 (extcall_arg_pair rs m) ll vl2 -> vl1 = vl2).
+ {
+ induction 1; intros vl2 EA; inv EA.
+ auto.
+ f_equal; eauto. }
+ intros. eapply C; eauto.
+Qed.
+
+Lemma semantics_determinate: forall p, determinate (semantics p).
+Proof.
+Ltac Equalities :=
+ match goal with
+ | [ H1: ?a = ?b, H2: ?a = ?c |- _ ] =>
+ rewrite H1 in H2; inv H2; Equalities
+ | _ => idtac
+ end.
+ intros; constructor; simpl; intros.
+- (* determ *)
+ inv H; inv H0; Equalities.
+ split. constructor. auto.
+ discriminate.
+ discriminate.
+ assert (vargs0 = vargs) by (eapply eval_builtin_args_determ; eauto). subst vargs0.
+ exploit external_call_determ. eexact H5. eexact H11. intros [A B].
+ split. auto. intros. destruct B; auto. subst. auto.
+ assert (args0 = args) by (eapply extcall_arguments_determ; eauto). subst args0.
+ exploit external_call_determ. eexact H3. eexact H8. intros [A B].
+ split. auto. intros. destruct B; auto. subst. auto.
+- (* trace length *)
+ red; intros. inv H; simpl.
+ omega.
+ eapply external_call_trace_length; eauto.
+ eapply external_call_trace_length; eauto.
+- (* initial states *)
+ inv H; inv H0. f_equal. congruence.
+- (* final no step *)
+ inv H. red; intros; red; intros. inv H; rewrite H0 in *; discriminate.
+- (* final states *)
+ inv H; inv H0. congruence.
+Qed.
+
+(** Classification functions for processor registers (used in Asmgenproof). *)
+
+Definition data_preg (r: preg) : bool :=
+ match r with
+ | IR X16 => false
+ | IR X30 => false
+ | IR _ => true
+ | FR _ => true
+ | CR _ => false
+ | SP => true
+ | PC => false
+ end.
diff --git a/aarch64/AsmToJSON.ml b/aarch64/AsmToJSON.ml
new file mode 100644
index 00000000..b7cfc152
--- /dev/null
+++ b/aarch64/AsmToJSON.ml
@@ -0,0 +1,24 @@
+(* *********************************************************************)
+(* *)
+(* 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. *)
+(* *)
+(* *********************************************************************)
+
+(* Functions to serialize AArch64 Asm to JSON *)
+
+(* Dummy function *)
+
+let destination: string option ref = ref None
+
+let sdump_folder = ref ""
+
+let print_if prog sourcename =
+ ()
+
+let pp_mnemonics pp = ()
diff --git a/aarch64/Asmexpand.ml b/aarch64/Asmexpand.ml
new file mode 100644
index 00000000..71bd0042
--- /dev/null
+++ b/aarch64/Asmexpand.ml
@@ -0,0 +1,436 @@
+(* *********************************************************************)
+(* *)
+(* 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. *)
+(* *)
+(* *********************************************************************)
+
+(* Expanding built-ins and some pseudo-instructions by rewriting
+ of the AArch64 assembly code. *)
+
+open Asm
+open Asmexpandaux
+open AST
+open Camlcoq
+module Ptrofs = Integers.Ptrofs
+
+exception Error of string
+
+(* Useful constants *)
+
+let _0 = Z.zero
+let _1 = Z.one
+let _2 = Z.of_sint 2
+let _4 = Z.of_sint 4
+let _8 = Z.of_sint 8
+let _16 = Z.of_sint 16
+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 [])
+
+let expand_addimm64 (dst: iregsp) (src: iregsp) n =
+ List.iter emit (Asmgen.addimm64 dst src n [])
+
+let expand_storeptr (src: ireg) (base: iregsp) ofs =
+ List.iter emit (Asmgen.storeptr src base ofs [])
+
+(* Handling of varargs *)
+
+(* Determine the number of int registers, FP registers, and stack locations
+ used to pass the fixed parameters. *)
+
+let rec next_arg_locations ir fr stk = function
+ | [] ->
+ (ir, fr, stk)
+ | (Tint | Tlong | Tany32 | Tany64) :: l ->
+ if ir < 8
+ then next_arg_locations (ir + 1) fr stk l
+ else next_arg_locations ir fr (stk + 8) l
+ | (Tfloat | Tsingle) :: l ->
+ if fr < 8
+ then next_arg_locations ir (fr + 1) stk l
+ else next_arg_locations ir fr (stk + 8) l
+
+(* Allocate memory on the stack and use it to save the registers
+ used for parameter passing. As an optimization, do not save
+ the registers used to pass the fixed parameters. *)
+
+let int_param_regs = [| X0; X1; X2; X3; X4; X5; X6; X7 |]
+let float_param_regs = [| D0; D1; D2; D3; D4; D5; D6; D7 |]
+let size_save_register_area = 8*8 + 8*16
+
+let save_parameter_registers ir fr =
+ emit (Psubimm(X, XSP, XSP, Z.of_uint size_save_register_area));
+ let i = ref ir in
+ while !i < 8 do
+ let pos = 8*16 + !i*8 in
+ if !i land 1 = 0 then begin
+ emit (Pstp(int_param_regs.(!i), int_param_regs.(!i + 1),
+ ADimm(XSP, Z.of_uint pos)));
+ i := !i + 2
+ end else begin
+ emit (Pstrx(int_param_regs.(!i), ADimm(XSP, Z.of_uint pos)));
+ i := !i + 1
+ end
+ done;
+ for i = fr to 7 do
+ let pos = i*16 in
+ emit (Pstrd(float_param_regs.(i), ADimm(XSP, Z.of_uint pos)))
+ done
+
+(* Initialize a va_list as per va_start.
+ Register r points to the following struct:
+
+ typedef struct __va_list {
+ void *__stack; // next stack parameter
+ void *__gr_top; // top of the save area for int regs
+ void *__vr_top; // top of the save area for float regs
+ int__gr_offs; // offset from gr_top to next int reg
+ int__vr_offs; // offset from gr_top to next FP reg
+ }
+*)
+
+let current_function_stacksize = ref 0L
+
+let expand_builtin_va_start r =
+ if not (is_current_function_variadic ()) then
+ invalid_arg "Fatal error: va_start used in non-vararg function";
+ let (ir, fr, stk) =
+ next_arg_locations 0 0 0 (get_current_function_args ()) in
+ let stack_ofs = Int64.(add !current_function_stacksize (of_int stk))
+ and gr_top_ofs = !current_function_stacksize
+ and vr_top_ofs = Int64.(sub !current_function_stacksize 64L)
+ and gr_offs = - ((8 - ir) * 8)
+ and vr_offs = - ((8 - fr) * 16) in
+ (* va->__stack = sp + stack_ofs *)
+ expand_addimm64 (RR1 X16) XSP (coqint_of_camlint64 stack_ofs);
+ emit (Pstrx(X16, ADimm(RR1 r, coqint_of_camlint64 0L)));
+ (* va->__gr_top = sp + gr_top_ofs *)
+ if gr_top_ofs <> stack_ofs then
+ expand_addimm64 (RR1 X16) XSP (coqint_of_camlint64 gr_top_ofs);
+ emit (Pstrx(X16, ADimm(RR1 r, coqint_of_camlint64 8L)));
+ (* va->__vr_top = sp + vr_top_ofs *)
+ expand_addimm64 (RR1 X16) XSP (coqint_of_camlint64 vr_top_ofs);
+ emit (Pstrx(X16, ADimm(RR1 r, coqint_of_camlint64 16L)));
+ (* va->__gr_offs = gr_offs *)
+ expand_loadimm32 X16 (coqint_of_camlint (Int32.of_int gr_offs));
+ emit (Pstrw(X16, ADimm(RR1 r, coqint_of_camlint64 24L)));
+ (* va->__vr_offs = vr_offs *)
+ expand_loadimm32 X16 (coqint_of_camlint (Int32.of_int vr_offs));
+ emit (Pstrw(X16, ADimm(RR1 r, coqint_of_camlint64 28L)))
+
+(* Handling of annotations *)
+
+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) ->
+ if dst <> src then emit (Pfmov (dst, src))
+ | _, _ ->
+ raise (Error "ill-formed __builtin_annot_val")
+
+(* Handling of memcpy *)
+
+(* We assume unaligned memory accesses are efficient. Hence we use
+ memory accesses as wide as we can, up to 16 bytes.
+ Temporary registers used: x15 x16 x17 x29 x30. *)
+
+let offset_in_range ofs =
+ let ofs = Z.to_int64 ofs in 0L <= ofs && ofs < 0x1000L
+
+let memcpy_small_arg sz arg tmp =
+ match arg with
+ | BA (IR r) ->
+ (RR1 r, _0)
+ | BA_addrstack ofs ->
+ if offset_in_range ofs
+ && offset_in_range (Ptrofs.add ofs (Ptrofs.repr (Z.of_uint sz)))
+ then (XSP, ofs)
+ else begin expand_addimm64 (RR1 tmp) XSP ofs; (RR1 tmp, _0) end
+ | _ ->
+ assert false
+
+let expand_builtin_memcpy_small sz al src dst =
+ let (tsrc, tdst) =
+ if dst <> BA (IR 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 =
+ if sz >= 16 then begin
+ emit (Pldp(X16, X30, ADimm(rsrc, osrc)));
+ emit (Pstp(X16, X30, ADimm(rdst, odst)));
+ copy (Ptrofs.add osrc _16) (Ptrofs.add odst _16) (sz - 16)
+ end
+ else if sz >= 8 then begin
+ emit (Pldrx(X16, ADimm(rsrc, osrc)));
+ emit (Pstrx(X16, ADimm(rdst, odst)));
+ copy (Ptrofs.add osrc _8) (Ptrofs.add odst _8) (sz - 8)
+ end
+ else if sz >= 4 then begin
+ emit (Pldrw(X16, ADimm(rsrc, osrc)));
+ emit (Pstrw(X16, ADimm(rdst, odst)));
+ copy (Ptrofs.add osrc _4) (Ptrofs.add odst _4) (sz - 4)
+ end
+ else if sz >= 2 then begin
+ emit (Pldrh(W, X16, ADimm(rsrc, osrc)));
+ emit (Pstrh(X16, ADimm(rdst, odst)));
+ copy (Ptrofs.add osrc _2) (Ptrofs.add odst _2) (sz - 2)
+ end
+ else if sz >= 1 then begin
+ emit (Pldrb(W, X16, ADimm(rsrc, osrc)));
+ emit (Pstrb(X16, ADimm(rdst, odst)));
+ copy (Ptrofs.add osrc _1) (Ptrofs.add odst _1) (sz - 1)
+ end
+ in copy osrc odst sz
+
+let memcpy_big_arg arg tmp =
+ match arg with
+ | BA (IR r) -> emit (Pmov(RR1 tmp, RR1 r))
+ | BA_addrstack ofs -> expand_addimm64 (RR1 tmp) XSP ofs
+ | _ -> assert false
+
+let expand_builtin_memcpy_big sz al src dst =
+ assert (sz >= 16);
+ memcpy_big_arg src X30;
+ memcpy_big_arg dst X29;
+ let lbl = new_label () in
+ expand_loadimm32 X15 (Z.of_uint (sz / 16));
+ emit (Plabel lbl);
+ emit (Pldp(X16, X17, ADpostincr(RR1 X30, _16)));
+ emit (Pstp(X16, X17, ADpostincr(RR1 X29, _16)));
+ emit (Psubimm(W, RR1 X15, RR1 X15, _1));
+ emit (Pcbnz(W, X15, lbl));
+ if sz mod 16 >= 8 then begin
+ emit (Pldrx(X16, ADpostincr(RR1 X30, _8)));
+ emit (Pstrx(X16, ADpostincr(RR1 X29, _8)))
+ end;
+ if sz mod 8 >= 4 then begin
+ emit (Pldrw(X16, ADpostincr(RR1 X30, _4)));
+ emit (Pstrw(X16, ADpostincr(RR1 X29, _4)))
+ end;
+ if sz mod 4 >= 2 then begin
+ emit (Pldrh(W, X16, ADpostincr(RR1 X30, _2)));
+ emit (Pstrh(X16, ADpostincr(RR1 X29, _2)))
+ end;
+ if sz mod 2 >= 1 then begin
+ emit (Pldrb(W, X16, ADpostincr(RR1 X30, _1)));
+ emit (Pstrb(X16, ADpostincr(RR1 X29, _1)))
+ end
+
+let expand_builtin_memcpy sz al args =
+ let (dst, src) =
+ match args with [d; s] -> (d, s) | _ -> assert false in
+ if sz < 64
+ then expand_builtin_memcpy_small sz al src dst
+ else expand_builtin_memcpy_big sz al src dst
+
+(* Handling of volatile reads and writes *)
+
+let expand_builtin_vload_common chunk base ofs res =
+ let addr = ADimm(base, ofs) in
+ match chunk, res with
+ | Mint8unsigned, BR(IR res) ->
+ emit (Pldrb(W, res, addr))
+ | Mint8signed, BR(IR res) ->
+ emit (Pldrsb(W, res, addr))
+ | Mint16unsigned, BR(IR res) ->
+ emit (Pldrh(W, res, addr))
+ | Mint16signed, BR(IR res) ->
+ emit (Pldrsh(W, res, addr))
+ | Mint32, BR(IR res) ->
+ emit (Pldrw(res, addr))
+ | Mint64, BR(IR res) ->
+ emit (Pldrx(res, addr))
+ | Mfloat32, BR(FR res) ->
+ emit (Pldrs(res, addr))
+ | Mfloat64, BR(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_addrstack ofs] ->
+ if offset_in_range (Z.add ofs (Memdata.size_chunk chunk)) then
+ expand_builtin_vload_common chunk XSP ofs res
+ else begin
+ 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)] ->
+ if offset_in_range (Z.add ofs (Memdata.size_chunk chunk)) then
+ expand_builtin_vload_common chunk (RR1 addr) ofs res
+ else begin
+ expand_addimm64 (RR1 X16) (RR1 addr) ofs; (* X16 <- addr + ofs *)
+ expand_builtin_vload_common chunk (RR1 X16) _0 res
+ end
+ | _ ->
+ assert false
+
+let expand_builtin_vstore_common chunk base ofs src =
+ let addr = ADimm(base, ofs) in
+ match chunk, src with
+ | (Mint8signed | Mint8unsigned), BA(IR src) ->
+ emit (Pstrb(src, addr))
+ | (Mint16signed | Mint16unsigned), BA(IR src) ->
+ emit (Pstrh(src, addr))
+ | Mint32, BA(IR src) ->
+ emit (Pstrw(src, addr))
+ | Mint64, BA(IR src) ->
+ emit (Pstrx(src, addr))
+ | Mfloat32, BA(FR src) ->
+ emit (Pstrs(src, addr))
+ | Mfloat64, BA(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_addrstack ofs; src] ->
+ if offset_in_range (Z.add ofs (Memdata.size_chunk chunk)) then
+ expand_builtin_vstore_common chunk XSP ofs src
+ else begin
+ 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] ->
+ if offset_in_range (Z.add ofs (Memdata.size_chunk chunk)) then
+ expand_builtin_vstore_common chunk (RR1 addr) ofs src
+ else begin
+ expand_addimm64 (RR1 X16) (RR1 addr) ofs; (* X16 <- addr + ofs *)
+ expand_builtin_vstore_common chunk (RR1 X16) _0 src
+ end
+ | _ ->
+ assert false
+
+(* Handling of compiler-inlined builtins *)
+
+let expand_builtin_inline name args res =
+ match name, args, res with
+ (* Synchronization *)
+ | "__builtin_membar", [], _ ->
+ ()
+ | "__builtin_nop", [], _ ->
+ emit Pnop
+ (* Byte swap *)
+ | ("__builtin_bswap" | "__builtin_bswap32"), [BA(IR a1)], BR(IR res) ->
+ emit (Prev(W, res, a1))
+ | "__builtin_bswap64", [BA(IR a1)], BR(IR res) ->
+ emit (Prev(X, res, a1))
+ | "__builtin_bswap16", [BA(IR a1)], BR(IR 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) ->
+ emit (Pclz(W, res, a1))
+ | ("__builtin_clzl" | "__builtin_clzll"), [BA(IR a1)], BR(IR res) ->
+ emit (Pclz(X, res, a1))
+ | "__builtin_cls", [BA(IR a1)], BR(IR res) ->
+ emit (Pcls(W, res, a1))
+ | ("__builtin_clsl" | "__builtin_clsll"), [BA(IR a1)], BR(IR res) ->
+ emit (Pcls(X, res, a1))
+ (* Float arithmetic *)
+ | "__builtin_fabs", [BA(FR a1)], BR(FR res) ->
+ emit (Pfabs(D, res, a1))
+ | "__builtin_fsqrt", [BA(FR a1)], BR(FR res) ->
+ emit (Pfsqrt(D, res, a1))
+ | "__builtin_fmadd", [BA(FR a1); BA(FR a2); BA(FR a3)], BR(FR res) ->
+ emit (Pfmadd(D, res, a1, a2, a3))
+ | "__builtin_fmsub", [BA(FR a1); BA(FR a2); BA(FR a3)], BR(FR res) ->
+ emit (Pfmsub(D, res, a1, a2, a3))
+ | "__builtin_fnmadd", [BA(FR a1); BA(FR a2); BA(FR a3)], BR(FR res) ->
+ emit (Pfnmadd(D, res, a1, a2, a3))
+ | "__builtin_fnmsub", [BA(FR a1); BA(FR a2); BA(FR a3)], BR(FR res) ->
+ emit (Pfnmsub(D, res, a1, a2, a3))
+ (* Vararg *)
+ | "__builtin_va_start", [BA(IR a)], _ ->
+ expand_builtin_va_start a
+ (* Catch-all *)
+ | _ ->
+ raise (Error ("unrecognized builtin " ^ name))
+
+(* Expansion of instructions *)
+
+let expand_instruction instr =
+ match instr with
+ | Pallocframe (sz, ofs) ->
+ emit (Pmov (RR1 X29, XSP));
+ if is_current_function_variadic() then begin
+ let (ir, fr, _) =
+ next_arg_locations 0 0 0 (get_current_function_args ()) in
+ save_parameter_registers ir fr;
+ current_function_stacksize :=
+ Int64.(add (Z.to_int64 sz) (of_int size_save_register_area))
+ end else begin
+ current_function_stacksize := Z.to_int64 sz
+ end;
+ expand_addimm64 XSP XSP (Ptrofs.repr (Z.neg sz));
+ expand_storeptr X29 XSP ofs
+ | Pfreeframe (sz, ofs) ->
+ expand_addimm64 XSP XSP (coqint_of_camlint64 !current_function_stacksize)
+ | Pcvtx2w rd ->
+ (* no code generated, the upper 32 bits of rd will be ignored *)
+ ()
+ | Pbuiltin (ef,args,res) ->
+ begin match ef with
+ | EF_builtin (name,sg) ->
+ expand_builtin_inline (camlstring_of_coqstring name) args res
+ | EF_vload chunk ->
+ expand_builtin_vload chunk args res
+ | EF_vstore chunk ->
+ expand_builtin_vstore chunk args
+ | EF_annot_val (kind,txt,targ) ->
+ expand_annot_val kind txt targ args res
+ | EF_memcpy(sz, al) ->
+ expand_builtin_memcpy (Z.to_int sz) (Z.to_int al) args
+ | EF_annot _ | EF_debug _ | EF_inline_asm _ ->
+ emit instr
+ | _ ->
+ assert false
+ end
+ | _ ->
+ emit instr
+
+let int_reg_to_dwarf r = 0 (* TODO *)
+
+let float_reg_to_dwarf r = 0 (* TODO *)
+
+let preg_to_dwarf = function
+ | IR r -> int_reg_to_dwarf r
+ | FR r -> float_reg_to_dwarf r
+ | _ -> assert false
+
+let expand_function id fn =
+ try
+ set_current_function fn;
+ expand id (* sp= *) 2 preg_to_dwarf expand_instruction fn.fn_code;
+ Errors.OK (get_current_function ())
+ with Error s ->
+ Errors.Error (Errors.msg (coqstring_of_camlstring s))
+
+let expand_fundef id = function
+ | Internal f ->
+ begin match expand_function id f with
+ | Errors.OK tf -> Errors.OK (Internal tf)
+ | Errors.Error msg -> Errors.Error msg
+ end
+ | External ef ->
+ Errors.OK (External ef)
+
+let expand_program (p: Asm.program) : Asm.program Errors.res =
+ AST.transform_partial_program2 expand_fundef (fun id v -> Errors.OK v) p
diff --git a/aarch64/Asmgen.v b/aarch64/Asmgen.v
new file mode 100644
index 00000000..1c0e41a1
--- /dev/null
+++ b/aarch64/Asmgen.v
@@ -0,0 +1,1151 @@
+(* *********************************************************************)
+(* *)
+(* 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. *)
+
+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.
+
+(** 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).
+
+(** 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
+ 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
+ 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.
+
+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: 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
+ 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]. *)
+
+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.
+
+(** 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 -> 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
+ 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.
+
+(** Translation of loads and stores *)
+
+Definition transl_load (chunk: memory_chunk) (addr: Op.addressing)
+ (args: list mreg) (dst: mreg) (k: code) : res code :=
+ 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.
+
+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.
+
+(** Register-indexed loads and stores *)
+
+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).
+
+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")
+ 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")
+ 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) :=
+ 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 chunk addr args dst =>
+ transl_load 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))
+ 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
+ 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
+ | nil => OK nil
+ | i1 :: il' =>
+ do k <- transl_code f il' (it1_is_parent it1p i1);
+ transl_instr f i1 it1p k
+ 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)
+ end.
+
+Definition transl_code' (f: Mach.function) (il: list Mach.instruction) (it1p: bool) :=
+ transl_code_rec f il it1p (fun c => OK c).
+
+(** 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 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_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_fundef (f: Mach.fundef) : res Asm.fundef :=
+ transf_partial_fundef transf_function f.
+
+Definition transf_program (p: Mach.program) : res Asm.program :=
+ transform_partial_program transf_fundef p.
diff --git a/aarch64/Asmgenproof.v b/aarch64/Asmgenproof.v
new file mode 100644
index 00000000..eeff1956
--- /dev/null
+++ b/aarch64/Asmgenproof.v
@@ -0,0 +1,1026 @@
+(* *********************************************************************)
+(* *)
+(* 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; 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; 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 chunk addr args dst k c,
+ transl_load chunk addr args dst k = OK c -> tail_nolabel k c.
+Proof.
+ unfold transl_load; intros; 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. 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),
+ 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)) ->
+ 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]]].
+ 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') ->
+ 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]]]]].
+ 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.
+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') ->
+ 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]]]]].
+ 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.
+- 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.
+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'),
+ (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. simpl; congruence.
+
+- (* 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]]].
+ exists rs'; split. eauto.
+ split. eapply agree_set_mreg; eauto with asmgen. congruence.
+ simpl; congruence.
+
+- (* 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]].
+ exists rs'; split. eauto.
+ split. eapply agree_undef_regs; eauto with asmgen.
+ simpl; intros. rewrite Q; auto with asmgen.
+
+- (* 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]]].
+ exists rs1; split. eauto.
+ split. eapply agree_set_mreg. eapply agree_set_mreg; eauto. congruence. auto with asmgen.
+ simpl; intros. rewrite R; auto with asmgen.
+ apply preg_of_not_X29; 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]]].
+ 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.
+ simpl; intros. rewrite U; auto with asmgen.
+ apply preg_of_not_X29; 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]]].
+ exists rs2; split. eauto. split.
+ apply agree_set_undef_mreg with rs0; auto.
+ apply Val.lessdef_trans with v'; auto.
+ simpl; intros. InvBooleans.
+ rewrite R; auto. apply preg_of_not_X29; auto.
+Local Transparent destroyed_by_op.
+ destruct op; try exact I; simpl; congruence.
+
+- (* Mload *)
+ 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]]].
+ exists rs2; split. eauto.
+ split. eapply agree_set_undef_mreg; eauto. congruence.
+ simpl; congruence.
+
+- (* 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]].
+ exists rs2; split. eauto.
+ split. eapply agree_undef_regs; eauto with asmgen.
+ simpl; congruence.
+
+- (* 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.
+
+- (* 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.
+
+- (* 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).
+ exists jmp; exists k; exists rs'.
+ split. eexact A.
+ split. apply agree_exten with rs0; auto with asmgen.
+ exact B.
+
+- (* 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).
+ 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.
+ simpl; congruence.
+
+- (* 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.
+
+- (* 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).
+ 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.
+
+- (* 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.
+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).
+ apply senv_preserved.
+ eexact transf_initial_states.
+ eexact transf_final_states.
+ exact step_simulation.
+Qed.
+
+End PRESERVATION.
diff --git a/aarch64/Asmgenproof1.v b/aarch64/Asmgenproof1.v
new file mode 100644
index 00000000..d60ad2bc
--- /dev/null
+++ b/aarch64/Asmgenproof1.v
@@ -0,0 +1,1836 @@
+(* *********************************************************************)
+(* *)
+(* 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: auxiliary results. *)
+
+Require Import Recdef Coqlib Zwf Zbits.
+Require Import Maps Errors AST Integers Floats Values Memory Globalenvs.
+Require Import Op Locations Mach Asm Conventions.
+Require Import Asmgen.
+Require Import Asmgenproof0.
+
+Local Transparent Archi.ptr64.
+
+(** Properties of registers *)
+
+Lemma preg_of_iregsp_not_PC: forall r, preg_of_iregsp r <> PC.
+Proof.
+ destruct r; simpl; congruence.
+Qed.
+Hint Resolve preg_of_iregsp_not_PC: asmgen.
+
+Lemma preg_of_not_X16: forall r, preg_of r <> X16.
+Proof.
+ destruct r; simpl; congruence.
+Qed.
+
+Lemma ireg_of_not_X16: forall r x, ireg_of r = OK x -> x <> X16.
+Proof.
+ unfold ireg_of; intros. destruct (preg_of r) eqn:E; inv H.
+ red; intros; subst x. elim (preg_of_not_X16 r); auto.
+Qed.
+
+Lemma ireg_of_not_X16': forall r x, ireg_of r = OK x -> IR x <> IR X16.
+Proof.
+ intros. apply ireg_of_not_X16 in H. congruence.
+Qed.
+
+Hint Resolve preg_of_not_X16 ireg_of_not_X16 ireg_of_not_X16': asmgen.
+
+(** Useful simplification tactic *)
+
+
+Ltac Simplif :=
+ ((rewrite nextinstr_inv by eauto with asmgen)
+ || (rewrite nextinstr_inv1 by eauto with asmgen)
+ || (rewrite Pregmap.gss)
+ || (rewrite nextinstr_pc)
+ || (rewrite Pregmap.gso by eauto with asmgen)); auto with asmgen.
+
+Ltac Simpl := repeat Simplif.
+
+(** * Correctness of ARM constructor functions *)
+
+Section CONSTRUCTORS.
+
+Variable ge: genv.
+Variable fn: function.
+
+(** Decomposition of integer literals *)
+
+Inductive wf_decomposition: list (Z * Z) -> Prop :=
+ | wf_decomp_nil:
+ wf_decomposition nil
+ | wf_decomp_cons: forall m n p l,
+ n = Zzero_ext 16 m -> 0 <= p -> wf_decomposition l ->
+ wf_decomposition ((n, p) :: l).
+
+Lemma decompose_int_wf:
+ forall N n p, 0 <= p -> wf_decomposition (decompose_int N n p).
+Proof.
+Local Opaque Zzero_ext.
+ induction N as [ | N]; simpl; intros.
+- constructor.
+- set (frag := Zzero_ext 16 (Z.shiftr n p)) in *. destruct (Z.eqb frag 0).
++ apply IHN. omega.
++ econstructor. reflexivity. omega. apply IHN; omega.
+Qed.
+
+Fixpoint recompose_int (accu: Z) (l: list (Z * Z)) : Z :=
+ match l with
+ | nil => accu
+ | (n, p) :: l => recompose_int (Zinsert accu n p 16) l
+ end.
+
+Lemma decompose_int_correct:
+ forall N n p accu,
+ 0 <= p ->
+ (forall i, p <= i -> Z.testbit accu i = false) ->
+ (forall i, 0 <= i < p + Z.of_nat N * 16 ->
+ Z.testbit (recompose_int accu (decompose_int N n p)) i =
+ if zlt i p then Z.testbit accu i else Z.testbit n i).
+Proof.
+ induction N as [ | N]; intros until accu; intros PPOS ABOVE i RANGE.
+- simpl. rewrite zlt_true; auto. xomega.
+- rewrite inj_S in RANGE. simpl.
+ set (frag := Zzero_ext 16 (Z.shiftr n p)).
+ assert (FRAG: forall i, p <= i < p + 16 -> Z.testbit n i = Z.testbit frag (i - p)).
+ { unfold frag; intros. rewrite Zzero_ext_spec by omega. rewrite zlt_true by omega.
+ rewrite Z.shiftr_spec by omega. f_equal; omega. }
+ destruct (Z.eqb_spec frag 0).
++ rewrite IHN.
+* destruct (zlt i p). rewrite zlt_true by omega. auto.
+ destruct (zlt i (p + 16)); auto.
+ rewrite ABOVE by omega. rewrite FRAG by omega. rewrite e, Z.testbit_0_l. auto.
+* omega.
+* intros; apply ABOVE; omega.
+* xomega.
++ simpl. rewrite IHN.
+* destruct (zlt i (p + 16)).
+** rewrite Zinsert_spec by omega. unfold proj_sumbool.
+ rewrite zlt_true by omega.
+ destruct (zlt i p).
+ rewrite zle_false by omega. auto.
+ rewrite zle_true by omega. simpl. symmetry; apply FRAG; omega.
+** rewrite Z.ldiff_spec, Z.shiftl_spec by omega.
+ change 65535 with (two_p 16 - 1). rewrite Ztestbit_two_p_m1 by omega.
+ rewrite zlt_false by omega. rewrite zlt_false by omega. apply andb_true_r.
+* omega.
+* intros. rewrite Zinsert_spec by omega. unfold proj_sumbool.
+ rewrite zle_true by omega. rewrite zlt_false by omega. simpl.
+ apply ABOVE. omega.
+* xomega.
+Qed.
+
+Corollary decompose_int_eqmod: forall N n,
+ eqmod (two_power_nat (N * 16)%nat) (recompose_int 0 (decompose_int N n 0)) n.
+Proof.
+ intros; apply eqmod_same_bits; intros.
+ rewrite decompose_int_correct. apply zlt_false; omega.
+ omega. intros; apply Z.testbit_0_l. xomega.
+Qed.
+
+Corollary decompose_notint_eqmod: forall N n,
+ eqmod (two_power_nat (N * 16)%nat)
+ (Z.lnot (recompose_int 0 (decompose_int N (Z.lnot n) 0))) n.
+Proof.
+ intros; apply eqmod_same_bits; intros.
+ rewrite Z.lnot_spec, decompose_int_correct.
+ rewrite zlt_false by omega. rewrite Z.lnot_spec by omega. apply negb_involutive.
+ omega. intros; apply Z.testbit_0_l. xomega. omega.
+Qed.
+
+Lemma negate_decomposition_wf:
+ forall l, wf_decomposition l -> wf_decomposition (negate_decomposition l).
+Proof.
+ induction 1; simpl; econstructor; auto.
+ instantiate (1 := (Z.lnot m)).
+ apply equal_same_bits; intros.
+ rewrite H. change 65535 with (two_p 16 - 1).
+ rewrite Z.lxor_spec, !Zzero_ext_spec, Z.lnot_spec, Ztestbit_two_p_m1 by omega.
+ destruct (zlt i 16).
+ apply xorb_true_r.
+ auto.
+Qed.
+
+Lemma Zinsert_eqmod:
+ forall n x1 x2 y p l, 0 <= p -> 0 <= l ->
+ eqmod (two_power_nat n) x1 x2 ->
+ eqmod (two_power_nat n) (Zinsert x1 y p l) (Zinsert x2 y p l).
+Proof.
+ intros. apply eqmod_same_bits; intros. rewrite ! Zinsert_spec by omega.
+ destruct (zle p i && zlt i (p + l)); auto.
+ apply same_bits_eqmod with n; auto.
+Qed.
+
+Lemma Zinsert_0_l:
+ forall y p l,
+ 0 <= p -> 0 <= l ->
+ Z.shiftl (Zzero_ext l y) p = Zinsert 0 (Zzero_ext l y) p l.
+Proof.
+ intros. apply equal_same_bits; intros.
+ rewrite Zinsert_spec by omega. unfold proj_sumbool.
+ destruct (zlt i p); [rewrite zle_false by omega|rewrite zle_true by omega]; simpl.
+- rewrite Z.testbit_0_l, Z.shiftl_spec_low by auto. auto.
+- rewrite Z.shiftl_spec by omega.
+ destruct (zlt i (p + l)); auto.
+ rewrite Zzero_ext_spec, zlt_false, Z.testbit_0_l by omega. auto.
+Qed.
+
+Lemma recompose_int_negated:
+ forall l, wf_decomposition l ->
+ forall accu, recompose_int (Z.lnot accu) (negate_decomposition l) = Z.lnot (recompose_int accu l).
+Proof.
+ induction 1; intros accu; simpl.
+- auto.
+- rewrite <- IHwf_decomposition. f_equal. apply equal_same_bits; intros.
+ rewrite Z.lnot_spec, ! Zinsert_spec, Z.lxor_spec, Z.lnot_spec by omega.
+ unfold proj_sumbool.
+ destruct (zle p i); simpl; auto.
+ destruct (zlt i (p + 16)); simpl; auto.
+ change 65535 with (two_p 16 - 1).
+ rewrite Ztestbit_two_p_m1 by omega. rewrite zlt_true by omega.
+ apply xorb_true_r.
+Qed.
+
+Lemma exec_loadimm_k_w:
+ forall (rd: ireg) k m l,
+ wf_decomposition l ->
+ forall (rs: regset) accu,
+ rs#rd = Vint (Int.repr accu) ->
+ exists rs',
+ exec_straight_opt ge fn (loadimm_k W rd l k) rs m k rs' m
+ /\ rs'#rd = Vint (Int.repr (recompose_int accu l))
+ /\ forall r, r <> PC -> r <> rd -> rs'#r = rs#r.
+Proof.
+ induction 1; intros rs accu ACCU; simpl.
+- exists rs; split. apply exec_straight_opt_refl. auto.
+- destruct (IHwf_decomposition
+ (nextinstr (rs#rd <- (insert_in_int rs#rd n p 16)))
+ (Zinsert accu n p 16))
+ as (rs' & P & Q & R).
+ Simpl. rewrite ACCU. simpl. f_equal. apply Int.eqm_samerepr.
+ apply Zinsert_eqmod. auto. omega. apply Int.eqm_sym; apply Int.eqm_unsigned_repr.
+ exists rs'; split.
+ eapply exec_straight_opt_step_opt. simpl; eauto. auto. exact P.
+ split. exact Q. intros; Simpl. rewrite R by auto. Simpl.
+Qed.
+
+Lemma exec_loadimm_z_w:
+ forall rd l k rs m,
+ wf_decomposition l ->
+ exists rs',
+ exec_straight ge fn (loadimm_z W rd l k) rs m k rs' m
+ /\ rs'#rd = Vint (Int.repr (recompose_int 0 l))
+ /\ forall r, r <> PC -> r <> rd -> rs'#r = rs#r.
+Proof.
+ unfold loadimm_z; destruct 1.
+- econstructor; split.
+ apply exec_straight_one. simpl; eauto. auto.
+ split. Simpl.
+ intros; Simpl.
+- set (accu0 := Zinsert 0 n p 16).
+ set (rs1 := nextinstr (rs#rd <- (Vint (Int.repr accu0)))).
+ destruct (exec_loadimm_k_w rd k m l H1 rs1 accu0) as (rs2 & P & Q & R); auto.
+ unfold rs1; Simpl.
+ exists rs2; split.
+ eapply exec_straight_opt_step; eauto.
+ simpl. unfold rs1. do 5 f_equal. unfold accu0. rewrite H. apply Zinsert_0_l; omega.
+ reflexivity.
+ split. exact Q.
+ intros. rewrite R by auto. unfold rs1; Simpl.
+Qed.
+
+Lemma exec_loadimm_n_w:
+ forall rd l k rs m,
+ wf_decomposition l ->
+ exists rs',
+ exec_straight ge fn (loadimm_n W rd l k) rs m k rs' m
+ /\ rs'#rd = Vint (Int.repr (Z.lnot (recompose_int 0 l)))
+ /\ forall r, r <> PC -> r <> rd -> rs'#r = rs#r.
+Proof.
+ unfold loadimm_n; destruct 1.
+- econstructor; split.
+ apply exec_straight_one. simpl; eauto. auto.
+ split. Simpl.
+ intros; Simpl.
+- set (accu0 := Z.lnot (Zinsert 0 n p 16)).
+ set (rs1 := nextinstr (rs#rd <- (Vint (Int.repr accu0)))).
+ destruct (exec_loadimm_k_w rd k m (negate_decomposition l)
+ (negate_decomposition_wf l H1)
+ rs1 accu0) as (rs2 & P & Q & R).
+ unfold rs1; Simpl.
+ exists rs2; split.
+ eapply exec_straight_opt_step; eauto.
+ simpl. unfold rs1. do 5 f_equal.
+ unfold accu0. f_equal. rewrite H. apply Zinsert_0_l; omega.
+ reflexivity.
+ split. unfold accu0 in Q; rewrite recompose_int_negated in Q by auto. exact Q.
+ intros. rewrite R by auto. unfold rs1; Simpl.
+Qed.
+
+Lemma exec_loadimm32:
+ forall rd n k rs m,
+ exists rs',
+ exec_straight ge fn (loadimm32 rd n k) rs m k rs' m
+ /\ rs'#rd = Vint n
+ /\ forall r, r <> PC -> r <> rd -> rs'#r = rs#r.
+Proof.
+ unfold loadimm32, loadimm; intros.
+ destruct (is_logical_imm32 n).
+- econstructor; split.
+ apply exec_straight_one. simpl; eauto. auto.
+ split. Simpl. rewrite Int.repr_unsigned, Int.or_zero_l; auto.
+ intros; Simpl.
+- set (dz := decompose_int 2%nat (Int.unsigned n) 0).
+ set (dn := decompose_int 2%nat (Z.lnot (Int.unsigned n)) 0).
+ assert (A: Int.repr (recompose_int 0 dz) = n).
+ { transitivity (Int.repr (Int.unsigned n)).
+ apply Int.eqm_samerepr. apply decompose_int_eqmod.
+ apply Int.repr_unsigned. }
+ assert (B: Int.repr (Z.lnot (recompose_int 0 dn)) = n).
+ { transitivity (Int.repr (Int.unsigned n)).
+ apply Int.eqm_samerepr. apply decompose_notint_eqmod.
+ apply Int.repr_unsigned. }
+ destruct Nat.leb.
++ rewrite <- A. apply exec_loadimm_z_w. apply decompose_int_wf; omega.
++ rewrite <- B. apply exec_loadimm_n_w. apply decompose_int_wf; omega.
+Qed.
+
+Lemma exec_loadimm_k_x:
+ forall (rd: ireg) k m l,
+ wf_decomposition l ->
+ forall (rs: regset) accu,
+ rs#rd = Vlong (Int64.repr accu) ->
+ exists rs',
+ exec_straight_opt ge fn (loadimm_k X rd l k) rs m k rs' m
+ /\ rs'#rd = Vlong (Int64.repr (recompose_int accu l))
+ /\ forall r, r <> PC -> r <> rd -> rs'#r = rs#r.
+Proof.
+ induction 1; intros rs accu ACCU; simpl.
+- exists rs; split. apply exec_straight_opt_refl. auto.
+- destruct (IHwf_decomposition
+ (nextinstr (rs#rd <- (insert_in_long rs#rd n p 16)))
+ (Zinsert accu n p 16))
+ as (rs' & P & Q & R).
+ Simpl. rewrite ACCU. simpl. f_equal. apply Int64.eqm_samerepr.
+ apply Zinsert_eqmod. auto. omega. apply Int64.eqm_sym; apply Int64.eqm_unsigned_repr.
+ exists rs'; split.
+ eapply exec_straight_opt_step_opt. simpl; eauto. auto. exact P.
+ split. exact Q. intros; Simpl. rewrite R by auto. Simpl.
+Qed.
+
+Lemma exec_loadimm_z_x:
+ forall rd l k rs m,
+ wf_decomposition l ->
+ exists rs',
+ exec_straight ge fn (loadimm_z X rd l k) rs m k rs' m
+ /\ rs'#rd = Vlong (Int64.repr (recompose_int 0 l))
+ /\ forall r, r <> PC -> r <> rd -> rs'#r = rs#r.
+Proof.
+ unfold loadimm_z; destruct 1.
+- econstructor; split.
+ apply exec_straight_one. simpl; eauto. auto.
+ split. Simpl.
+ intros; Simpl.
+- set (accu0 := Zinsert 0 n p 16).
+ set (rs1 := nextinstr (rs#rd <- (Vlong (Int64.repr accu0)))).
+ destruct (exec_loadimm_k_x rd k m l H1 rs1 accu0) as (rs2 & P & Q & R); auto.
+ unfold rs1; Simpl.
+ exists rs2; split.
+ eapply exec_straight_opt_step; eauto.
+ simpl. unfold rs1. do 5 f_equal. unfold accu0. rewrite H. apply Zinsert_0_l; omega.
+ reflexivity.
+ split. exact Q.
+ intros. rewrite R by auto. unfold rs1; Simpl.
+Qed.
+
+Lemma exec_loadimm_n_x:
+ forall rd l k rs m,
+ wf_decomposition l ->
+ exists rs',
+ exec_straight ge fn (loadimm_n X rd l k) rs m k rs' m
+ /\ rs'#rd = Vlong (Int64.repr (Z.lnot (recompose_int 0 l)))
+ /\ forall r, r <> PC -> r <> rd -> rs'#r = rs#r.
+Proof.
+ unfold loadimm_n; destruct 1.
+- econstructor; split.
+ apply exec_straight_one. simpl; eauto. auto.
+ split. Simpl.
+ intros; Simpl.
+- set (accu0 := Z.lnot (Zinsert 0 n p 16)).
+ set (rs1 := nextinstr (rs#rd <- (Vlong (Int64.repr accu0)))).
+ destruct (exec_loadimm_k_x rd k m (negate_decomposition l)
+ (negate_decomposition_wf l H1)
+ rs1 accu0) as (rs2 & P & Q & R).
+ unfold rs1; Simpl.
+ exists rs2; split.
+ eapply exec_straight_opt_step; eauto.
+ simpl. unfold rs1. do 5 f_equal.
+ unfold accu0. f_equal. rewrite H. apply Zinsert_0_l; omega.
+ reflexivity.
+ split. unfold accu0 in Q; rewrite recompose_int_negated in Q by auto. exact Q.
+ intros. rewrite R by auto. unfold rs1; Simpl.
+Qed.
+
+Lemma exec_loadimm64:
+ forall rd n k rs m,
+ exists rs',
+ exec_straight ge fn (loadimm64 rd n k) rs m k rs' m
+ /\ rs'#rd = Vlong n
+ /\ forall r, r <> PC -> r <> rd -> rs'#r = rs#r.
+Proof.
+ unfold loadimm64, loadimm; intros.
+ destruct (is_logical_imm64 n).
+- econstructor; split.
+ apply exec_straight_one. simpl; eauto. auto.
+ split. Simpl. rewrite Int64.repr_unsigned, Int64.or_zero_l; auto.
+ intros; Simpl.
+- set (dz := decompose_int 4%nat (Int64.unsigned n) 0).
+ set (dn := decompose_int 4%nat (Z.lnot (Int64.unsigned n)) 0).
+ assert (A: Int64.repr (recompose_int 0 dz) = n).
+ { transitivity (Int64.repr (Int64.unsigned n)).
+ apply Int64.eqm_samerepr. apply decompose_int_eqmod.
+ apply Int64.repr_unsigned. }
+ assert (B: Int64.repr (Z.lnot (recompose_int 0 dn)) = n).
+ { transitivity (Int64.repr (Int64.unsigned n)).
+ apply Int64.eqm_samerepr. apply decompose_notint_eqmod.
+ apply Int64.repr_unsigned. }
+ destruct Nat.leb.
++ rewrite <- A. apply exec_loadimm_z_x. apply decompose_int_wf; omega.
++ rewrite <- B. apply exec_loadimm_n_x. apply decompose_int_wf; omega.
+Qed.
+
+(** Add immediate *)
+
+Lemma exec_addimm_aux_32:
+ forall (insn: iregsp -> iregsp -> Z -> instruction) (sem: val -> val -> val),
+ (forall rd r1 n rs m,
+ exec_instr ge fn (insn rd r1 n) rs m =
+ Next (nextinstr (rs#rd <- (sem rs#r1 (Vint (Int.repr n))))) m) ->
+ (forall v n1 n2, sem (sem v (Vint n1)) (Vint n2) = sem v (Vint (Int.add n1 n2))) ->
+ forall rd r1 n k rs m,
+ exists rs',
+ exec_straight ge fn (addimm_aux insn rd r1 (Int.unsigned n) k) rs m k rs' m
+ /\ rs'#rd = sem rs#r1 (Vint n)
+ /\ forall r, data_preg r = true -> r <> rd -> rs'#r = rs#r.
+Proof.
+ intros insn sem SEM ASSOC; intros. unfold addimm_aux.
+ set (nlo := Zzero_ext 12 (Int.unsigned n)). set (nhi := Int.unsigned n - nlo).
+ assert (E: Int.unsigned n = nhi + nlo) by (unfold nlo, nhi; omega).
+ rewrite <- (Int.repr_unsigned n).
+ destruct (Z.eqb_spec nhi 0); [|destruct (Z.eqb_spec nlo 0)].
+- econstructor; split. apply exec_straight_one. apply SEM. Simpl.
+ split. Simpl. do 3 f_equal; omega.
+ intros; Simpl.
+- econstructor; split. apply exec_straight_one. apply SEM. Simpl.
+ split. Simpl. do 3 f_equal; omega.
+ intros; Simpl.
+- econstructor; split. eapply exec_straight_two.
+ apply SEM. apply SEM. Simpl. Simpl.
+ split. Simpl. rewrite ASSOC. do 2 f_equal. apply Int.eqm_samerepr.
+ rewrite E. auto with ints.
+ intros; Simpl.
+Qed.
+
+Lemma exec_addimm32:
+ forall rd r1 n k rs m,
+ r1 <> X16 ->
+ exists rs',
+ exec_straight ge fn (addimm32 rd r1 n k) rs m k rs' m
+ /\ rs'#rd = Val.add rs#r1 (Vint n)
+ /\ forall r, data_preg r = true -> r <> rd -> rs'#r = rs#r.
+Proof.
+ intros. unfold addimm32. set (nn := Int.neg n).
+ destruct (Int.eq n (Int.zero_ext 24 n)); [| destruct (Int.eq nn (Int.zero_ext 24 nn))].
+- apply exec_addimm_aux_32 with (sem := Val.add). auto. intros; apply Val.add_assoc.
+- rewrite <- Val.sub_opp_add.
+ apply exec_addimm_aux_32 with (sem := Val.sub). auto.
+ intros. rewrite ! Val.sub_add_opp, Val.add_assoc. rewrite Int.neg_add_distr. auto.
+- destruct (Int.lt n Int.zero).
++ rewrite <- Val.sub_opp_add; fold nn.
+ edestruct (exec_loadimm32 X16 nn) as (rs1 & A & B & C).
+ econstructor; split.
+ eapply exec_straight_trans. eexact A. eapply exec_straight_one. simpl; eauto. auto.
+ split. Simpl. rewrite B, C; eauto with asmgen.
+ intros; Simpl.
++ edestruct (exec_loadimm32 X16 n) as (rs1 & A & B & C).
+ econstructor; split.
+ eapply exec_straight_trans. eexact A. eapply exec_straight_one. simpl; eauto. auto.
+ split. Simpl. rewrite B, C; eauto with asmgen.
+ intros; Simpl.
+Qed.
+
+Lemma exec_addimm_aux_64:
+ forall (insn: iregsp -> iregsp -> Z -> instruction) (sem: val -> val -> val),
+ (forall rd r1 n rs m,
+ exec_instr ge fn (insn rd r1 n) rs m =
+ Next (nextinstr (rs#rd <- (sem rs#r1 (Vlong (Int64.repr n))))) m) ->
+ (forall v n1 n2, sem (sem v (Vlong n1)) (Vlong n2) = sem v (Vlong (Int64.add n1 n2))) ->
+ forall rd r1 n k rs m,
+ exists rs',
+ exec_straight ge fn (addimm_aux insn rd r1 (Int64.unsigned n) k) rs m k rs' m
+ /\ rs'#rd = sem rs#r1 (Vlong n)
+ /\ forall r, data_preg r = true -> r <> rd -> rs'#r = rs#r.
+Proof.
+ intros insn sem SEM ASSOC; intros. unfold addimm_aux.
+ set (nlo := Zzero_ext 12 (Int64.unsigned n)). set (nhi := Int64.unsigned n - nlo).
+ assert (E: Int64.unsigned n = nhi + nlo) by (unfold nlo, nhi; omega).
+ rewrite <- (Int64.repr_unsigned n).
+ destruct (Z.eqb_spec nhi 0); [|destruct (Z.eqb_spec nlo 0)].
+- econstructor; split. apply exec_straight_one. apply SEM. Simpl.
+ split. Simpl. do 3 f_equal; omega.
+ intros; Simpl.
+- econstructor; split. apply exec_straight_one. apply SEM. Simpl.
+ split. Simpl. do 3 f_equal; omega.
+ intros; Simpl.
+- econstructor; split. eapply exec_straight_two.
+ apply SEM. apply SEM. Simpl. Simpl.
+ split. Simpl. rewrite ASSOC. do 2 f_equal. apply Int64.eqm_samerepr.
+ rewrite E. auto with ints.
+ intros; Simpl.
+Qed.
+
+Lemma exec_addimm64:
+ forall rd r1 n k rs m,
+ preg_of_iregsp r1 <> X16 ->
+ exists rs',
+ exec_straight ge fn (addimm64 rd r1 n k) rs m k rs' m
+ /\ rs'#rd = Val.addl rs#r1 (Vlong n)
+ /\ forall r, data_preg r = true -> r <> rd -> rs'#r = rs#r.
+Proof.
+ intros.
+ unfold addimm64. set (nn := Int64.neg n).
+ destruct (Int64.eq n (Int64.zero_ext 24 n)); [| destruct (Int64.eq nn (Int64.zero_ext 24 nn))].
+- apply exec_addimm_aux_64 with (sem := Val.addl). auto. intros; apply Val.addl_assoc.
+- rewrite <- Val.subl_opp_addl.
+ apply exec_addimm_aux_64 with (sem := Val.subl). auto.
+ intros. rewrite ! Val.subl_addl_opp, Val.addl_assoc. rewrite Int64.neg_add_distr. auto.
+- destruct (Int64.lt n Int64.zero).
++ rewrite <- Val.subl_opp_addl; fold nn.
+ edestruct (exec_loadimm64 X16 nn) as (rs1 & A & B & C).
+ econstructor; split.
+ eapply exec_straight_trans. eexact A. eapply exec_straight_one. simpl; eauto. Simpl.
+ split. Simpl. rewrite B, C; eauto with asmgen. simpl. rewrite Int64.shl'_zero. auto.
+ intros; Simpl.
++ edestruct (exec_loadimm64 X16 n) as (rs1 & A & B & C).
+ econstructor; split.
+ eapply exec_straight_trans. eexact A. eapply exec_straight_one. simpl; eauto. Simpl.
+ split. Simpl. rewrite B, C; eauto with asmgen. simpl. rewrite Int64.shl'_zero. auto.
+ intros; Simpl.
+Qed.
+
+(** Logical immediate *)
+
+Lemma exec_logicalimm32:
+ forall (insn1: ireg -> ireg0 -> Z -> instruction)
+ (insn2: ireg -> ireg0 -> ireg -> shift_op -> instruction)
+ (sem: val -> val -> val),
+ (forall rd r1 n rs m,
+ exec_instr ge fn (insn1 rd r1 n) rs m =
+ Next (nextinstr (rs#rd <- (sem rs##r1 (Vint (Int.repr n))))) m) ->
+ (forall rd r1 r2 s rs m,
+ exec_instr ge fn (insn2 rd r1 r2 s) rs m =
+ Next (nextinstr (rs#rd <- (sem rs##r1 (eval_shift_op_int rs#r2 s)))) m) ->
+ forall rd r1 n k rs m,
+ r1 <> X16 ->
+ exists rs',
+ exec_straight ge fn (logicalimm32 insn1 insn2 rd r1 n k) rs m k rs' m
+ /\ rs'#rd = sem rs#r1 (Vint n)
+ /\ forall r, data_preg r = true -> r <> rd -> rs'#r = rs#r.
+Proof.
+ intros until sem; intros SEM1 SEM2; intros. unfold logicalimm32.
+ destruct (is_logical_imm32 n).
+- econstructor; split.
+ apply exec_straight_one. apply SEM1. reflexivity.
+ split. Simpl. rewrite Int.repr_unsigned; auto. intros; Simpl.
+- edestruct (exec_loadimm32 X16 n) as (rs1 & A & B & C).
+ econstructor; split.
+ eapply exec_straight_trans. eexact A.
+ apply exec_straight_one. apply SEM2. reflexivity.
+ split. Simpl. f_equal; auto. apply C; auto with asmgen.
+ intros; Simpl.
+Qed.
+
+Lemma exec_logicalimm64:
+ forall (insn1: ireg -> ireg0 -> Z -> instruction)
+ (insn2: ireg -> ireg0 -> ireg -> shift_op -> instruction)
+ (sem: val -> val -> val),
+ (forall rd r1 n rs m,
+ exec_instr ge fn (insn1 rd r1 n) rs m =
+ Next (nextinstr (rs#rd <- (sem rs###r1 (Vlong (Int64.repr n))))) m) ->
+ (forall rd r1 r2 s rs m,
+ exec_instr ge fn (insn2 rd r1 r2 s) rs m =
+ Next (nextinstr (rs#rd <- (sem rs###r1 (eval_shift_op_long rs#r2 s)))) m) ->
+ forall rd r1 n k rs m,
+ r1 <> X16 ->
+ exists rs',
+ exec_straight ge fn (logicalimm64 insn1 insn2 rd r1 n k) rs m k rs' m
+ /\ rs'#rd = sem rs#r1 (Vlong n)
+ /\ forall r, data_preg r = true -> r <> rd -> rs'#r = rs#r.
+Proof.
+ intros until sem; intros SEM1 SEM2; intros. unfold logicalimm64.
+ destruct (is_logical_imm64 n).
+- econstructor; split.
+ apply exec_straight_one. apply SEM1. reflexivity.
+ split. Simpl. rewrite Int64.repr_unsigned. auto. intros; Simpl.
+- edestruct (exec_loadimm64 X16 n) as (rs1 & A & B & C).
+ econstructor; split.
+ eapply exec_straight_trans. eexact A.
+ apply exec_straight_one. apply SEM2. reflexivity.
+ split. Simpl. f_equal; auto. apply C; auto with asmgen.
+ intros; Simpl.
+Qed.
+
+(** Load address of symbol *)
+
+Lemma exec_loadsymbol: forall rd s ofs k rs m,
+ rd <> X16 \/ Archi.pic_code tt = false ->
+ exists rs',
+ exec_straight ge fn (loadsymbol rd s ofs k) rs m k rs' m
+ /\ rs'#rd = Genv.symbol_address ge s ofs
+ /\ forall r, data_preg r = true -> r <> rd -> rs'#r = rs#r.
+Proof.
+ unfold loadsymbol; intros. destruct (Archi.pic_code tt).
+- predSpec Ptrofs.eq Ptrofs.eq_spec ofs Ptrofs.zero.
++ subst ofs. econstructor; split.
+ apply exec_straight_one; [simpl; eauto | reflexivity].
+ split. Simpl. intros; Simpl.
++ exploit exec_addimm64. instantiate (1 := rd). simpl. destruct H; congruence.
+ intros (rs1 & A & B & C).
+ econstructor; split.
+ econstructor. simpl; eauto. auto. eexact A.
+ split. simpl in B; rewrite B. Simpl.
+ rewrite <- Genv.shift_symbol_address_64 by auto.
+ rewrite Ptrofs.add_zero_l, Ptrofs.of_int64_to_int64 by auto. auto.
+ intros. rewrite C by auto. Simpl.
+- econstructor; split.
+ eapply exec_straight_two. simpl; eauto. simpl; eauto. auto. auto.
+ split. Simpl. rewrite symbol_high_low; auto.
+ intros; Simpl.
+Qed.
+
+(** Shifted operands *)
+
+Remark transl_shift_not_none:
+ forall s a, transl_shift s a <> SOnone.
+Proof.
+ destruct s; intros; simpl; congruence.
+Qed.
+
+Remark or_zero_eval_shift_op_int:
+ forall v s, s <> SOnone -> Val.or (Vint Int.zero) (eval_shift_op_int v s) = eval_shift_op_int v s.
+Proof.
+ intros; destruct s; try congruence; destruct v; auto; simpl;
+ destruct (Int.ltu n Int.iwordsize); auto; rewrite Int.or_zero_l; auto.
+Qed.
+
+Remark or_zero_eval_shift_op_long:
+ forall v s, s <> SOnone -> Val.orl (Vlong Int64.zero) (eval_shift_op_long v s) = eval_shift_op_long v s.
+Proof.
+ intros; destruct s; try congruence; destruct v; auto; simpl;
+ destruct (Int.ltu n Int64.iwordsize'); auto; rewrite Int64.or_zero_l; auto.
+Qed.
+
+Remark add_zero_eval_shift_op_long:
+ forall v s, s <> SOnone -> Val.addl (Vlong Int64.zero) (eval_shift_op_long v s) = eval_shift_op_long v s.
+Proof.
+ intros; destruct s; try congruence; destruct v; auto; simpl;
+ destruct (Int.ltu n Int64.iwordsize'); auto; rewrite Int64.add_zero_l; auto.
+Qed.
+
+Lemma transl_eval_shift: forall s v (a: amount32),
+ eval_shift_op_int v (transl_shift s a) = eval_shift s v a.
+Proof.
+ intros. destruct s; simpl; auto.
+Qed.
+
+Lemma transl_eval_shift': forall s v (a: amount32),
+ Val.or (Vint Int.zero) (eval_shift_op_int v (transl_shift s a)) = eval_shift s v a.
+Proof.
+ intros. rewrite or_zero_eval_shift_op_int by (apply transl_shift_not_none).
+ apply transl_eval_shift.
+Qed.
+
+Lemma transl_eval_shiftl: forall s v (a: amount64),
+ eval_shift_op_long v (transl_shift s a) = eval_shiftl s v a.
+Proof.
+ intros. destruct s; simpl; auto.
+Qed.
+
+Lemma transl_eval_shiftl': forall s v (a: amount64),
+ Val.orl (Vlong Int64.zero) (eval_shift_op_long v (transl_shift s a)) = eval_shiftl s v a.
+Proof.
+ intros. rewrite or_zero_eval_shift_op_long by (apply transl_shift_not_none).
+ apply transl_eval_shiftl.
+Qed.
+
+Lemma transl_eval_shiftl'': forall s v (a: amount64),
+ Val.addl (Vlong Int64.zero) (eval_shift_op_long v (transl_shift s a)) = eval_shiftl s v a.
+Proof.
+ intros. rewrite add_zero_eval_shift_op_long by (apply transl_shift_not_none).
+ apply transl_eval_shiftl.
+Qed.
+
+(** Zero- and Sign- extensions *)
+
+Lemma exec_move_extended_base: forall rd r1 ex k rs m,
+ exists rs',
+ exec_straight ge fn (move_extended_base rd r1 ex k) rs m k rs' m
+ /\ rs' rd = match ex with Xsgn32 => Val.longofint rs#r1 | Xuns32 => Val.longofintu rs#r1 end
+ /\ forall r, r <> PC -> r <> rd -> rs'#r = rs#r.
+Proof.
+ unfold move_extended_base; destruct ex; econstructor;
+ (split; [apply exec_straight_one; [simpl;eauto|auto] | split; [Simpl|intros;Simpl]]).
+Qed.
+
+Lemma exec_move_extended: forall rd r1 ex (a: amount64) k rs m,
+ exists rs',
+ exec_straight ge fn (move_extended rd r1 ex a k) rs m k rs' m
+ /\ rs' rd = Op.eval_extend ex rs#r1 a
+ /\ forall r, r <> PC -> r <> rd -> rs'#r = rs#r.
+Proof.
+ unfold move_extended; intros. predSpec Int.eq Int.eq_spec a Int.zero.
+- exploit (exec_move_extended_base rd r1 ex). intros (rs' & A & B & C).
+ exists rs'; split. eexact A. split. unfold Op.eval_extend. rewrite H. rewrite B.
+ destruct ex, (rs r1); simpl; auto; rewrite Int64.shl'_zero; auto.
+ auto.
+- Local Opaque Val.addl.
+ exploit (exec_move_extended_base rd r1 ex). intros (rs' & A & B & C).
+ econstructor; split.
+ eapply exec_straight_trans. eexact A. apply exec_straight_one.
+ unfold exec_instr. change (SOlsl a) with (transl_shift Slsl a). rewrite transl_eval_shiftl''. eauto. auto.
+ split. Simpl. rewrite B. auto.
+ intros; Simpl.
+Qed.
+
+Lemma exec_arith_extended:
+ forall (sem: val -> val -> val)
+ (insnX: iregsp -> iregsp -> ireg -> extend_op -> instruction)
+ (insnS: ireg -> ireg0 -> ireg -> shift_op -> instruction),
+ (forall rd r1 r2 x rs m,
+ exec_instr ge fn (insnX rd r1 r2 x) rs m =
+ Next (nextinstr (rs#rd <- (sem rs#r1 (eval_extend rs#r2 x)))) m) ->
+ (forall rd r1 r2 s rs m,
+ exec_instr ge fn (insnS rd r1 r2 s) rs m =
+ Next (nextinstr (rs#rd <- (sem rs###r1 (eval_shift_op_long rs#r2 s)))) m) ->
+ forall (rd r1 r2: ireg) (ex: extension) (a: amount64) (k: code) rs m,
+ r1 <> X16 ->
+ exists rs',
+ exec_straight ge fn (arith_extended insnX insnS rd r1 r2 ex a k) rs m k rs' m
+ /\ rs'#rd = sem rs#r1 (Op.eval_extend ex rs#r2 a)
+ /\ forall r, data_preg r = true -> r <> rd -> rs'#r = rs#r.
+Proof.
+ intros sem insnX insnS EX ES; intros. unfold arith_extended. destruct (Int.ltu a (Int.repr 5)).
+- econstructor; split.
+ apply exec_straight_one. rewrite EX; eauto. auto.
+ split. Simpl. f_equal. destruct ex; auto.
+ intros; Simpl.
+- exploit (exec_move_extended_base X16 r2 ex). intros (rs' & A & B & C).
+ econstructor; split.
+ eapply exec_straight_trans. eexact A. apply exec_straight_one.
+ rewrite ES. eauto. auto.
+ split. Simpl. unfold ir0x. rewrite C by eauto with asmgen. f_equal.
+ rewrite B. destruct ex; auto.
+ intros; Simpl.
+Qed.
+
+(** Extended right shift *)
+
+Lemma exec_shrx32: forall (rd r1: ireg) (n: int) k v (rs: regset) m,
+ Val.shrx rs#r1 (Vint n) = Some v ->
+ r1 <> X16 ->
+ exists rs',
+ exec_straight ge fn (shrx32 rd r1 n k) rs m k rs' m
+ /\ rs'#rd = v
+ /\ forall r, data_preg r = true -> r <> rd -> rs'#r = rs#r.
+Proof.
+ unfold shrx32; intros. apply Val.shrx_shr_2 in H.
+ destruct (Int.eq n Int.zero) eqn:E.
+- econstructor; split. apply exec_straight_one; [simpl;eauto|auto].
+ split. Simpl. subst v; auto. intros; Simpl.
+- econstructor; split. eapply exec_straight_three.
+ unfold exec_instr. rewrite or_zero_eval_shift_op_int by congruence. eauto.
+ simpl; eauto.
+ unfold exec_instr. rewrite or_zero_eval_shift_op_int by congruence. eauto.
+ auto. auto. auto.
+ split. subst v; Simpl. intros; Simpl.
+Qed.
+
+Lemma exec_shrx64: forall (rd r1: ireg) (n: int) k v (rs: regset) m,
+ Val.shrxl rs#r1 (Vint n) = Some v ->
+ r1 <> X16 ->
+ exists rs',
+ exec_straight ge fn (shrx64 rd r1 n k) rs m k rs' m
+ /\ rs'#rd = v
+ /\ forall r, data_preg r = true -> r <> rd -> rs'#r = rs#r.
+Proof.
+ unfold shrx64; intros. apply Val.shrxl_shrl_2 in H.
+ destruct (Int.eq n Int.zero) eqn:E.
+- econstructor; split. apply exec_straight_one; [simpl;eauto|auto].
+ split. Simpl. subst v; auto. intros; Simpl.
+- econstructor; split. eapply exec_straight_three.
+ unfold exec_instr. rewrite or_zero_eval_shift_op_long by congruence. eauto.
+ simpl; eauto.
+ unfold exec_instr. rewrite or_zero_eval_shift_op_long by congruence. eauto.
+ auto. auto. auto.
+ split. subst v; Simpl. intros; Simpl.
+Qed.
+
+(** Condition bits *)
+
+Lemma compare_int_spec: forall rs v1 v2 m,
+ let rs' := compare_int rs v1 v2 m in
+ rs'#CN = (Val.negative (Val.sub v1 v2))
+ /\ rs'#CZ = (Val.cmpu (Mem.valid_pointer m) Ceq v1 v2)
+ /\ rs'#CC = (Val.cmpu (Mem.valid_pointer m) Cge v1 v2)
+ /\ rs'#CV = (Val.sub_overflow v1 v2).
+Proof.
+ intros; unfold rs'; auto.
+Qed.
+
+Lemma eval_testcond_compare_sint: forall c v1 v2 b rs m,
+ Val.cmp_bool c v1 v2 = Some b ->
+ eval_testcond (cond_for_signed_cmp c) (compare_int rs v1 v2 m) = Some b.
+Proof.
+ intros. generalize (compare_int_spec rs v1 v2 m).
+ set (rs' := compare_int rs v1 v2 m). intros (B & C & D & E).
+ unfold eval_testcond; rewrite B, C, D, E.
+ destruct v1; try discriminate; destruct v2; try discriminate.
+ simpl in H; inv H.
+ unfold Val.cmpu; simpl. destruct c; simpl.
+- destruct (Int.eq i i0); auto.
+- destruct (Int.eq i i0); auto.
+- rewrite Int.lt_sub_overflow. destruct (Int.lt i i0); auto.
+- rewrite Int.lt_sub_overflow, Int.not_lt.
+ destruct (Int.eq i i0), (Int.lt i i0); auto.
+- rewrite Int.lt_sub_overflow, (Int.lt_not i).
+ destruct (Int.eq i i0), (Int.lt i i0); auto.
+- rewrite Int.lt_sub_overflow. destruct (Int.lt i i0); auto.
+Qed.
+
+Lemma eval_testcond_compare_uint: forall c v1 v2 b rs m,
+ Val.cmpu_bool (Mem.valid_pointer m) c v1 v2 = Some b ->
+ eval_testcond (cond_for_unsigned_cmp c) (compare_int rs v1 v2 m) = Some b.
+Proof.
+ intros. generalize (compare_int_spec rs v1 v2 m).
+ set (rs' := compare_int rs v1 v2 m). intros (B & C & D & E).
+ unfold eval_testcond; rewrite B, C, D, E.
+ destruct v1; try discriminate; destruct v2; try discriminate.
+ simpl in H; inv H.
+ unfold Val.cmpu; simpl. destruct c; simpl.
+- destruct (Int.eq i i0); auto.
+- destruct (Int.eq i i0); auto.
+- destruct (Int.ltu i i0); auto.
+- rewrite (Int.not_ltu i). destruct (Int.eq i i0), (Int.ltu i i0); auto.
+- rewrite (Int.ltu_not i). destruct (Int.eq i i0), (Int.ltu i i0); auto.
+- destruct (Int.ltu i i0); auto.
+Qed.
+
+Lemma compare_long_spec: forall rs v1 v2 m,
+ let rs' := compare_long rs v1 v2 m in
+ rs'#CN = (Val.negativel (Val.subl v1 v2))
+ /\ rs'#CZ = (Val.maketotal (Val.cmplu (Mem.valid_pointer m) Ceq v1 v2))
+ /\ rs'#CC = (Val.maketotal (Val.cmplu (Mem.valid_pointer m) Cge v1 v2))
+ /\ rs'#CV = (Val.subl_overflow v1 v2).
+Proof.
+ intros; unfold rs'; auto.
+Qed.
+
+Remark int64_sub_overflow:
+ forall x y,
+ Int.xor (Int.repr (Int64.unsigned (Int64.sub_overflow x y Int64.zero)))
+ (Int.repr (Int64.unsigned (Int64.negative (Int64.sub x y)))) =
+ (if Int64.lt x y then Int.one else Int.zero).
+Proof.
+ intros.
+ transitivity (Int.repr (Int64.unsigned (if Int64.lt x y then Int64.one else Int64.zero))).
+ rewrite <- (Int64.lt_sub_overflow x y).
+ unfold Int64.sub_overflow, Int64.negative.
+ set (s := Int64.signed x - Int64.signed y - Int64.signed Int64.zero).
+ destruct (zle Int64.min_signed s && zle s Int64.max_signed);
+ destruct (Int64.lt (Int64.sub x y) Int64.zero);
+ auto.
+ destruct (Int64.lt x y); auto.
+Qed.
+
+Lemma eval_testcond_compare_slong: forall c v1 v2 b rs m,
+ Val.cmpl_bool c v1 v2 = Some b ->
+ eval_testcond (cond_for_signed_cmp c) (compare_long rs v1 v2 m) = Some b.
+Proof.
+ intros. generalize (compare_long_spec rs v1 v2 m).
+ set (rs' := compare_long rs v1 v2 m). intros (B & C & D & E).
+ unfold eval_testcond; rewrite B, C, D, E.
+ destruct v1; try discriminate; destruct v2; try discriminate.
+ simpl in H; inv H.
+ unfold Val.cmplu; simpl. destruct c; simpl.
+- destruct (Int64.eq i i0); auto.
+- destruct (Int64.eq i i0); auto.
+- rewrite int64_sub_overflow. destruct (Int64.lt i i0); auto.
+- rewrite int64_sub_overflow, Int64.not_lt.
+ destruct (Int64.eq i i0), (Int64.lt i i0); auto.
+- rewrite int64_sub_overflow, (Int64.lt_not i).
+ destruct (Int64.eq i i0), (Int64.lt i i0); auto.
+- rewrite int64_sub_overflow. destruct (Int64.lt i i0); auto.
+Qed.
+
+Lemma eval_testcond_compare_ulong: forall c v1 v2 b rs m,
+ Val.cmplu_bool (Mem.valid_pointer m) c v1 v2 = Some b ->
+ eval_testcond (cond_for_unsigned_cmp c) (compare_long rs v1 v2 m) = Some b.
+Proof.
+ intros. generalize (compare_long_spec rs v1 v2 m).
+ set (rs' := compare_long rs v1 v2 m). intros (B & C & D & E).
+ unfold eval_testcond; rewrite B, C, D, E; unfold Val.cmplu.
+ destruct v1; try discriminate; destruct v2; try discriminate; simpl in H.
+- (* int-int *)
+ inv H. destruct c; simpl.
++ destruct (Int64.eq i i0); auto.
++ destruct (Int64.eq i i0); auto.
++ destruct (Int64.ltu i i0); auto.
++ rewrite (Int64.not_ltu i). destruct (Int64.eq i i0), (Int64.ltu i i0); auto.
++ rewrite (Int64.ltu_not i). destruct (Int64.eq i i0), (Int64.ltu i i0); auto.
++ destruct (Int64.ltu i i0); auto.
+- (* int-ptr *)
+ simpl.
+ destruct (Int64.eq i Int64.zero &&
+ (Mem.valid_pointer m b0 (Ptrofs.unsigned i0)
+ || Mem.valid_pointer m b0 (Ptrofs.unsigned i0 - 1))); try discriminate.
+ destruct c; simpl in H; inv H; reflexivity.
+- (* ptr-int *)
+ simpl.
+ destruct (Int64.eq i0 Int64.zero &&
+ (Mem.valid_pointer m b0 (Ptrofs.unsigned i)
+ || Mem.valid_pointer m b0 (Ptrofs.unsigned i - 1))); try discriminate.
+ destruct c; simpl in H; inv H; reflexivity.
+- (* ptr-ptr *)
+ simpl.
+ destruct (eq_block b0 b1).
++ destruct ((Mem.valid_pointer m b0 (Ptrofs.unsigned i)
+ || Mem.valid_pointer m b0 (Ptrofs.unsigned i - 1)) &&
+ (Mem.valid_pointer m b1 (Ptrofs.unsigned i0)
+ || Mem.valid_pointer m b1 (Ptrofs.unsigned i0 - 1)));
+ inv H.
+ destruct c; simpl.
+* destruct (Ptrofs.eq i i0); auto.
+* destruct (Ptrofs.eq i i0); auto.
+* destruct (Ptrofs.ltu i i0); auto.
+* rewrite (Ptrofs.not_ltu i). destruct (Ptrofs.eq i i0), (Ptrofs.ltu i i0); auto.
+* rewrite (Ptrofs.ltu_not i). destruct (Ptrofs.eq i i0), (Ptrofs.ltu i i0); auto.
+* destruct (Ptrofs.ltu i i0); auto.
++ destruct (Mem.valid_pointer m b0 (Ptrofs.unsigned i) &&
+ Mem.valid_pointer m b1 (Ptrofs.unsigned i0)); try discriminate.
+ destruct c; simpl in H; inv H; reflexivity.
+Qed.
+
+Lemma compare_float_spec: forall rs f1 f2,
+ let rs' := compare_float rs (Vfloat f1) (Vfloat f2) in
+ rs'#CN = (Val.of_bool (Float.cmp Clt f1 f2))
+ /\ rs'#CZ = (Val.of_bool (Float.cmp Ceq f1 f2))
+ /\ rs'#CC = (Val.of_bool (negb (Float.cmp Clt f1 f2)))
+ /\ rs'#CV = (Val.of_bool (negb (Float.ordered f1 f2))).
+Proof.
+ intros; auto.
+Qed.
+
+Lemma eval_testcond_compare_float: forall c v1 v2 b rs,
+ Val.cmpf_bool c v1 v2 = Some b ->
+ eval_testcond (cond_for_float_cmp c) (compare_float rs v1 v2) = Some b.
+Proof.
+ intros. destruct v1; try discriminate; destruct v2; simpl in H; inv H.
+ generalize (compare_float_spec rs f f0).
+ set (rs' := compare_float rs (Vfloat f) (Vfloat f0)).
+ intros (B & C & D & E).
+ unfold eval_testcond; rewrite B, C, D, E.
+Local Transparent Float.cmp Float.ordered.
+ unfold Float.cmp, Float.ordered;
+ destruct c; destruct (Float.compare f f0) as [[]|]; reflexivity.
+Qed.
+
+Lemma eval_testcond_compare_not_float: forall c v1 v2 b rs,
+ option_map negb (Val.cmpf_bool c v1 v2) = Some b ->
+ eval_testcond (cond_for_float_not_cmp c) (compare_float rs v1 v2) = Some b.
+Proof.
+ intros. destruct v1; try discriminate; destruct v2; simpl in H; inv H.
+ generalize (compare_float_spec rs f f0).
+ set (rs' := compare_float rs (Vfloat f) (Vfloat f0)).
+ intros (B & C & D & E).
+ unfold eval_testcond; rewrite B, C, D, E.
+Local Transparent Float.cmp Float.ordered.
+ unfold Float.cmp, Float.ordered;
+ destruct c; destruct (Float.compare f f0) as [[]|]; reflexivity.
+Qed.
+
+Lemma compare_single_spec: forall rs f1 f2,
+ let rs' := compare_single rs (Vsingle f1) (Vsingle f2) in
+ rs'#CN = (Val.of_bool (Float32.cmp Clt f1 f2))
+ /\ rs'#CZ = (Val.of_bool (Float32.cmp Ceq f1 f2))
+ /\ rs'#CC = (Val.of_bool (negb (Float32.cmp Clt f1 f2)))
+ /\ rs'#CV = (Val.of_bool (negb (Float32.ordered f1 f2))).
+Proof.
+ intros; auto.
+Qed.
+
+Lemma eval_testcond_compare_single: forall c v1 v2 b rs,
+ Val.cmpfs_bool c v1 v2 = Some b ->
+ eval_testcond (cond_for_float_cmp c) (compare_single rs v1 v2) = Some b.
+Proof.
+ intros. destruct v1; try discriminate; destruct v2; simpl in H; inv H.
+ generalize (compare_single_spec rs f f0).
+ set (rs' := compare_single rs (Vsingle f) (Vsingle f0)).
+ intros (B & C & D & E).
+ unfold eval_testcond; rewrite B, C, D, E.
+Local Transparent Float32.cmp Float32.ordered.
+ unfold Float32.cmp, Float32.ordered;
+ destruct c; destruct (Float32.compare f f0) as [[]|]; reflexivity.
+Qed.
+
+Lemma eval_testcond_compare_not_single: forall c v1 v2 b rs,
+ option_map negb (Val.cmpfs_bool c v1 v2) = Some b ->
+ eval_testcond (cond_for_float_not_cmp c) (compare_single rs v1 v2) = Some b.
+Proof.
+ intros. destruct v1; try discriminate; destruct v2; simpl in H; inv H.
+ generalize (compare_single_spec rs f f0).
+ set (rs' := compare_single rs (Vsingle f) (Vsingle f0)).
+ intros (B & C & D & E).
+ unfold eval_testcond; rewrite B, C, D, E.
+Local Transparent Float32.cmp Float32.ordered.
+ unfold Float32.cmp, Float32.ordered;
+ destruct c; destruct (Float32.compare f f0) as [[]|]; reflexivity.
+Qed.
+
+Remark compare_float_inv: forall rs v1 v2 r,
+ match r with CR _ => False | _ => True end ->
+ (nextinstr (compare_float rs v1 v2))#r = (nextinstr rs)#r.
+Proof.
+ intros; unfold compare_float.
+ destruct r; try contradiction; destruct v1; auto; destruct v2; auto.
+Qed.
+
+Remark compare_single_inv: forall rs v1 v2 r,
+ match r with CR _ => False | _ => True end ->
+ (nextinstr (compare_single rs v1 v2))#r = (nextinstr rs)#r.
+Proof.
+ intros; unfold compare_single.
+ destruct r; try contradiction; destruct v1; auto; destruct v2; auto.
+Qed.
+
+(** Translation of conditionals *)
+
+Ltac ArgsInv :=
+ repeat (match goal with
+ | [ H: Error _ = OK _ |- _ ] => discriminate
+ | [ H: match ?args with nil => _ | _ :: _ => _ end = OK _ |- _ ] => destruct args
+ | [ H: bind _ _ = OK _ |- _ ] => monadInv H
+ | [ H: match _ with left _ => _ | right _ => assertion_failed end = OK _ |- _ ] => monadInv H; ArgsInv
+ | [ H: match _ with true => _ | false => assertion_failed end = OK _ |- _ ] => monadInv H; ArgsInv
+ end);
+ subst;
+ repeat (match goal with
+ | [ H: ireg_of _ = OK _ |- _ ] => simpl in *; rewrite (ireg_of_eq _ _ H) in *
+ | [ H: freg_of _ = OK _ |- _ ] => simpl in *; rewrite (freg_of_eq _ _ H) in *
+ end).
+
+Lemma transl_cond_correct:
+ forall cond args k c rs m,
+ transl_cond cond args k = OK c ->
+ exists rs',
+ exec_straight ge fn c rs m k rs' m
+ /\ (forall b,
+ eval_condition cond (map rs (map preg_of args)) m = Some b ->
+ eval_testcond (cond_for_cond cond) rs' = Some b)
+ /\ forall r, data_preg r = true -> rs'#r = rs#r.
+Proof.
+ intros until m; intros TR. destruct cond; simpl in TR; ArgsInv.
+- (* Ccomp *)
+ econstructor; split. apply exec_straight_one. simpl; eauto. auto.
+ split; intros. apply eval_testcond_compare_sint; auto.
+ destruct r; reflexivity || discriminate.
+- (* Ccompu *)
+ econstructor; split. apply exec_straight_one. simpl; eauto. auto.
+ split; intros. apply eval_testcond_compare_uint; auto.
+ destruct r; reflexivity || discriminate.
+- (* Ccompimm *)
+ destruct (is_arith_imm32 n); [|destruct (is_arith_imm32 (Int.neg n))].
++ econstructor; split. apply exec_straight_one. simpl; eauto. auto.
+ split; intros. rewrite Int.repr_unsigned. apply eval_testcond_compare_sint; auto.
+ destruct r; reflexivity || discriminate.
++ econstructor; split.
+ apply exec_straight_one. simpl. rewrite Int.repr_unsigned, Int.neg_involutive. eauto. auto.
+ split; intros. apply eval_testcond_compare_sint; auto.
+ destruct r; reflexivity || discriminate.
++ exploit (exec_loadimm32 X16 n). intros (rs' & A & B & C).
+ econstructor; split.
+ eapply exec_straight_trans. eexact A. apply exec_straight_one.
+ simpl. rewrite B, C by eauto with asmgen. eauto. auto.
+ split; intros. apply eval_testcond_compare_sint; auto.
+ transitivity (rs' r). destruct r; reflexivity || discriminate. auto with asmgen.
+- (* Ccompuimm *)
+ destruct (is_arith_imm32 n); [|destruct (is_arith_imm32 (Int.neg n))].
++ econstructor; split. apply exec_straight_one. simpl; eauto. auto.
+ split; intros. rewrite Int.repr_unsigned. apply eval_testcond_compare_uint; auto.
+ destruct r; reflexivity || discriminate.
++ econstructor; split.
+ apply exec_straight_one. simpl. rewrite Int.repr_unsigned, Int.neg_involutive. eauto. auto.
+ split; intros. apply eval_testcond_compare_uint; auto.
+ destruct r; reflexivity || discriminate.
++ exploit (exec_loadimm32 X16 n). intros (rs' & A & B & C).
+ econstructor; split.
+ eapply exec_straight_trans. eexact A. apply exec_straight_one.
+ simpl. rewrite B, C by eauto with asmgen. eauto. auto.
+ split; intros. apply eval_testcond_compare_uint; auto.
+ transitivity (rs' r). destruct r; reflexivity || discriminate. auto with asmgen.
+- (* Ccompshift *)
+ econstructor; split. apply exec_straight_one. simpl; eauto. auto.
+ split; intros. rewrite transl_eval_shift. apply eval_testcond_compare_sint; auto.
+ destruct r; reflexivity || discriminate.
+- (* Ccompushift *)
+ econstructor; split. apply exec_straight_one. simpl; eauto. auto.
+ split; intros. rewrite transl_eval_shift. apply eval_testcond_compare_uint; auto.
+ destruct r; reflexivity || discriminate.
+- (* Cmaskzero *)
+ destruct (is_logical_imm32 n).
++ econstructor; split. apply exec_straight_one. simpl; eauto. auto.
+ split; intros. rewrite Int.repr_unsigned. apply (eval_testcond_compare_sint Ceq); auto.
+ destruct r; reflexivity || discriminate.
++ exploit (exec_loadimm32 X16 n). intros (rs' & A & B & C).
+ econstructor; split.
+ eapply exec_straight_trans. eexact A.
+ apply exec_straight_one. simpl. rewrite B, C by eauto with asmgen. eauto. auto.
+ split; intros. apply (eval_testcond_compare_sint Ceq); auto.
+ transitivity (rs' r). destruct r; reflexivity || discriminate. auto with asmgen.
+- (* Cmasknotzero *)
+ destruct (is_logical_imm32 n).
++ econstructor; split. apply exec_straight_one. simpl; eauto. auto.
+ split; intros. rewrite Int.repr_unsigned. apply (eval_testcond_compare_sint Cne); auto.
+ destruct r; reflexivity || discriminate.
++ exploit (exec_loadimm32 X16 n). intros (rs' & A & B & C).
+ econstructor; split.
+ eapply exec_straight_trans. eexact A.
+ apply exec_straight_one. simpl. rewrite B, C by eauto with asmgen. eauto. auto.
+ split; intros. apply (eval_testcond_compare_sint Cne); auto.
+ transitivity (rs' r). destruct r; reflexivity || discriminate. auto with asmgen.
+- (* Ccompl *)
+ econstructor; split. apply exec_straight_one. simpl; eauto. auto.
+ split; intros. apply eval_testcond_compare_slong; auto.
+ destruct r; reflexivity || discriminate.
+- (* Ccomplu *)
+ econstructor; split. apply exec_straight_one. simpl; eauto. auto.
+ split; intros. apply eval_testcond_compare_ulong; auto.
+ destruct r; reflexivity || discriminate.
+- (* Ccomplimm *)
+ destruct (is_arith_imm64 n); [|destruct (is_arith_imm64 (Int64.neg n))].
++ econstructor; split. apply exec_straight_one. simpl; eauto. auto.
+ split; intros. rewrite Int64.repr_unsigned. apply eval_testcond_compare_slong; auto.
+ destruct r; reflexivity || discriminate.
++ econstructor; split.
+ apply exec_straight_one. simpl. rewrite Int64.repr_unsigned, Int64.neg_involutive. eauto. auto.
+ split; intros. apply eval_testcond_compare_slong; auto.
+ destruct r; reflexivity || discriminate.
++ exploit (exec_loadimm64 X16 n). intros (rs' & A & B & C).
+ econstructor; split.
+ eapply exec_straight_trans. eexact A. apply exec_straight_one.
+ simpl. rewrite B, C by eauto with asmgen. eauto. auto.
+ split; intros. apply eval_testcond_compare_slong; auto.
+ transitivity (rs' r). destruct r; reflexivity || discriminate. auto with asmgen.
+- (* Ccompluimm *)
+ destruct (is_arith_imm64 n); [|destruct (is_arith_imm64 (Int64.neg n))].
++ econstructor; split. apply exec_straight_one. simpl; eauto. auto.
+ split; intros. rewrite Int64.repr_unsigned. apply eval_testcond_compare_ulong; auto.
+ destruct r; reflexivity || discriminate.
++ econstructor; split.
+ apply exec_straight_one. simpl. rewrite Int64.repr_unsigned, Int64.neg_involutive. eauto. auto.
+ split; intros. apply eval_testcond_compare_ulong; auto.
+ destruct r; reflexivity || discriminate.
++ exploit (exec_loadimm64 X16 n). intros (rs' & A & B & C).
+ econstructor; split.
+ eapply exec_straight_trans. eexact A. apply exec_straight_one.
+ simpl. rewrite B, C by eauto with asmgen. eauto. auto.
+ split; intros. apply eval_testcond_compare_ulong; auto.
+ transitivity (rs' r). destruct r; reflexivity || discriminate. auto with asmgen.
+- (* Ccomplshift *)
+ econstructor; split. apply exec_straight_one. simpl; eauto. auto.
+ split; intros. rewrite transl_eval_shiftl. apply eval_testcond_compare_slong; auto.
+ destruct r; reflexivity || discriminate.
+- (* Ccomplushift *)
+ econstructor; split. apply exec_straight_one. simpl; eauto. auto.
+ split; intros. rewrite transl_eval_shiftl. apply eval_testcond_compare_ulong; auto.
+ destruct r; reflexivity || discriminate.
+- (* Cmasklzero *)
+ destruct (is_logical_imm64 n).
++ econstructor; split. apply exec_straight_one. simpl; eauto. auto.
+ split; intros. rewrite Int64.repr_unsigned. apply (eval_testcond_compare_slong Ceq); auto.
+ destruct r; reflexivity || discriminate.
++ exploit (exec_loadimm64 X16 n). intros (rs' & A & B & C).
+ econstructor; split.
+ eapply exec_straight_trans. eexact A.
+ apply exec_straight_one. simpl. rewrite B, C by eauto with asmgen. eauto. auto.
+ split; intros. apply (eval_testcond_compare_slong Ceq); auto.
+ transitivity (rs' r). destruct r; reflexivity || discriminate. auto with asmgen.
+- (* Cmasknotzero *)
+ destruct (is_logical_imm64 n).
++ econstructor; split. apply exec_straight_one. simpl; eauto. auto.
+ split; intros. rewrite Int64.repr_unsigned. apply (eval_testcond_compare_slong Cne); auto.
+ destruct r; reflexivity || discriminate.
++ exploit (exec_loadimm64 X16 n). intros (rs' & A & B & C).
+ econstructor; split.
+ eapply exec_straight_trans. eexact A.
+ apply exec_straight_one. simpl. rewrite B, C by eauto with asmgen. eauto. auto.
+ split; intros. apply (eval_testcond_compare_slong Cne); auto.
+ transitivity (rs' r). destruct r; reflexivity || discriminate. auto with asmgen.
+- (* Ccompf *)
+ econstructor; split. apply exec_straight_one. simpl; eauto.
+ rewrite compare_float_inv; auto.
+ split; intros. apply eval_testcond_compare_float; auto.
+ destruct r; discriminate || rewrite compare_float_inv; auto.
+- (* Cnotcompf *)
+ econstructor; split. apply exec_straight_one. simpl; eauto.
+ rewrite compare_float_inv; auto.
+ split; intros. apply eval_testcond_compare_not_float; auto.
+ destruct r; discriminate || rewrite compare_float_inv; auto.
+- (* Ccompfzero *)
+ econstructor; split. apply exec_straight_one. simpl; eauto.
+ rewrite compare_float_inv; auto.
+ split; intros. apply eval_testcond_compare_float; auto.
+ destruct r; discriminate || rewrite compare_float_inv; auto.
+- (* Cnotcompfzero *)
+ econstructor; split. apply exec_straight_one. simpl; eauto.
+ rewrite compare_float_inv; auto.
+ split; intros. apply eval_testcond_compare_not_float; auto.
+ destruct r; discriminate || rewrite compare_float_inv; auto.
+- (* Ccompfs *)
+ econstructor; split. apply exec_straight_one. simpl; eauto.
+ rewrite compare_single_inv; auto.
+ split; intros. apply eval_testcond_compare_single; auto.
+ destruct r; discriminate || rewrite compare_single_inv; auto.
+- (* Cnotcompfs *)
+ econstructor; split. apply exec_straight_one. simpl; eauto.
+ rewrite compare_single_inv; auto.
+ split; intros. apply eval_testcond_compare_not_single; auto.
+ destruct r; discriminate || rewrite compare_single_inv; auto.
+- (* Ccompfszero *)
+ econstructor; split. apply exec_straight_one. simpl; eauto.
+ rewrite compare_single_inv; auto.
+ split; intros. apply eval_testcond_compare_single; auto.
+ destruct r; discriminate || rewrite compare_single_inv; auto.
+- (* Cnotcompfszero *)
+ econstructor; split. apply exec_straight_one. simpl; eauto.
+ rewrite compare_single_inv; auto.
+ split; intros. apply eval_testcond_compare_not_single; auto.
+ destruct r; discriminate || rewrite compare_single_inv; auto.
+Qed.
+
+(** Translation of conditional branches *)
+
+Lemma transl_cond_branch_correct:
+ forall cond args lbl k c rs m b,
+ transl_cond_branch cond args lbl k = OK c ->
+ eval_condition cond (map rs (map preg_of args)) m = Some b ->
+ exists rs' insn,
+ exec_straight_opt ge fn c rs m (insn :: k) rs' m
+ /\ exec_instr ge fn insn rs' m =
+ (if b then goto_label fn lbl rs' m else Next (nextinstr rs') m)
+ /\ forall r, data_preg r = true -> rs'#r = rs#r.
+Proof.
+ intros until b; intros TR EV.
+ assert (DFL:
+ transl_cond_branch_default cond args lbl k = OK c ->
+ exists rs' insn,
+ exec_straight_opt ge fn c rs m (insn :: k) rs' m
+ /\ exec_instr ge fn insn rs' m =
+ (if b then goto_label fn lbl rs' m else Next (nextinstr rs') m)
+ /\ forall r, data_preg r = true -> rs'#r = rs#r).
+ {
+ unfold transl_cond_branch_default; intros.
+ exploit transl_cond_correct; eauto. intros (rs' & A & B & C).
+ exists rs', (Pbc (cond_for_cond cond) lbl); split.
+ apply exec_straight_opt_intro. eexact A.
+ split; auto. simpl. rewrite (B b) by auto. auto.
+ }
+Local Opaque transl_cond transl_cond_branch_default.
+ destruct args as [ | a1 args]; simpl in TR; auto.
+ destruct args as [ | a2 args]; simpl in TR; auto.
+ destruct cond; simpl in TR; auto.
+- (* Ccompimm *)
+ destruct c0; auto; destruct (Int.eq n Int.zero) eqn:N0; auto;
+ apply Int.same_if_eq in N0; subst n; ArgsInv.
++ (* Ccompimm Cne 0 *)
+ do 2 econstructor; split.
+ apply exec_straight_opt_refl.
+ split; auto. simpl. destruct (rs x); simpl in EV; inv EV. simpl. auto.
++ (* Ccompimm Ceq 0 *)
+ do 2 econstructor; split.
+ apply exec_straight_opt_refl.
+ split; auto. simpl. destruct (rs x); simpl in EV; inv EV. simpl. destruct (Int.eq i Int.zero); auto.
+- (* Ccompuimm *)
+ destruct c0; auto; destruct (Int.eq n Int.zero) eqn:N0; auto;
+ apply Int.same_if_eq in N0; subst n; ArgsInv.
++ (* Ccompuimm Cne 0 *)
+ do 2 econstructor; split.
+ apply exec_straight_opt_refl.
+ split; auto. simpl. rewrite EV. auto.
++ (* Ccompuimm Ceq 0 *)
+ do 2 econstructor; split.
+ apply exec_straight_opt_refl.
+ split; auto. simpl. rewrite (Val.negate_cmpu_bool (Mem.valid_pointer m) Cne), EV. destruct b; auto.
+- (* Cmaskzero *)
+ destruct (Int.is_power2 n) as [bit|] eqn:P2; auto. ArgsInv.
+ do 2 econstructor; split.
+ apply exec_straight_opt_refl.
+ split; auto. simpl.
+ erewrite <- Int.mul_pow2, Int.mul_commut, Int.mul_one by eauto.
+ rewrite (Val.negate_cmp_bool Ceq), EV. destruct b; auto.
+- (* Cmasknotzero *)
+ destruct (Int.is_power2 n) as [bit|] eqn:P2; auto. ArgsInv.
+ do 2 econstructor; split.
+ apply exec_straight_opt_refl.
+ split; auto. simpl.
+ erewrite <- Int.mul_pow2, Int.mul_commut, Int.mul_one by eauto.
+ rewrite EV. auto.
+- (* Ccomplimm *)
+ destruct c0; auto; destruct (Int64.eq n Int64.zero) eqn:N0; auto;
+ apply Int64.same_if_eq in N0; subst n; ArgsInv.
++ (* Ccomplimm Cne 0 *)
+ do 2 econstructor; split.
+ apply exec_straight_opt_refl.
+ split; auto. simpl. destruct (rs x); simpl in EV; inv EV. simpl. auto.
++ (* Ccomplimm Ceq 0 *)
+ do 2 econstructor; split.
+ apply exec_straight_opt_refl.
+ split; auto. simpl. destruct (rs x); simpl in EV; inv EV. simpl. destruct (Int64.eq i Int64.zero); auto.
+- (* Ccompluimm *)
+ destruct c0; auto; destruct (Int64.eq n Int64.zero) eqn:N0; auto;
+ apply Int64.same_if_eq in N0; subst n; ArgsInv.
++ (* Ccompluimm Cne 0 *)
+ do 2 econstructor; split.
+ apply exec_straight_opt_refl.
+ split; auto. simpl. rewrite EV. auto.
++ (* Ccompluimm Ceq 0 *)
+ do 2 econstructor; split.
+ apply exec_straight_opt_refl.
+ split; auto. simpl. rewrite (Val.negate_cmplu_bool (Mem.valid_pointer m) Cne), EV. destruct b; auto.
+- (* Cmasklzero *)
+ destruct (Int64.is_power2' n) as [bit|] eqn:P2; auto. ArgsInv.
+ do 2 econstructor; split.
+ apply exec_straight_opt_refl.
+ split; auto. simpl.
+ erewrite <- Int64.mul_pow2', Int64.mul_commut, Int64.mul_one by eauto.
+ rewrite (Val.negate_cmpl_bool Ceq), EV. destruct b; auto.
+- (* Cmasklnotzero *)
+ destruct (Int64.is_power2' n) as [bit|] eqn:P2; auto. ArgsInv.
+ do 2 econstructor; split.
+ apply exec_straight_opt_refl.
+ split; auto. simpl.
+ erewrite <- Int64.mul_pow2', Int64.mul_commut, Int64.mul_one by eauto.
+ rewrite EV. auto.
+Qed.
+
+(** Translation of arithmetic operations *)
+
+Ltac SimplEval H :=
+ match type of H with
+ | Some _ = None _ => discriminate
+ | Some _ = Some _ => inv H
+ | ?a = Some ?b => let A := fresh in assert (A: Val.maketotal a = b) by (rewrite H; reflexivity)
+end.
+
+Ltac TranslOpSimpl :=
+ econstructor; split;
+ [ apply exec_straight_one; [simpl; eauto | reflexivity]
+ | split; [ rewrite ? transl_eval_shift, ? transl_eval_shiftl;
+ apply Val.lessdef_same; Simpl; fail
+ | intros; Simpl; fail ] ].
+
+Ltac TranslOpBase :=
+ econstructor; split;
+ [ apply exec_straight_one; [simpl; eauto | reflexivity]
+ | split; [ rewrite ? transl_eval_shift, ? transl_eval_shiftl; Simpl
+ | intros; Simpl; fail ] ].
+
+Lemma transl_op_correct:
+ forall op args res k (rs: regset) m v c,
+ transl_op op args res k = OK c ->
+ eval_operation ge (rs#SP) op (map rs (map preg_of args)) m = Some v ->
+ exists rs',
+ exec_straight ge fn c rs m k rs' m
+ /\ Val.lessdef v rs'#(preg_of res)
+ /\ forall r, data_preg r = true -> r <> preg_of res -> preg_notin r (destroyed_by_op op) -> rs' r = rs r.
+Proof.
+Local Opaque Int.eq Int64.eq Val.add Val.addl Int.zwordsize Int64.zwordsize.
+ intros until c; intros TR EV.
+ unfold transl_op in TR; destruct op; ArgsInv; simpl in EV; SimplEval EV; try TranslOpSimpl.
+- (* move *)
+ destruct (preg_of res) eqn:RR; try discriminate; destruct (preg_of m0) eqn:R1; inv TR.
++ TranslOpSimpl.
++ TranslOpSimpl.
+- (* intconst *)
+ exploit exec_loadimm32. intros (rs' & A & B & C).
+ exists rs'; split. eexact A. split. rewrite B; auto. intros; auto with asmgen.
+- (* longconst *)
+ exploit exec_loadimm64. intros (rs' & A & B & C).
+ exists rs'; split. eexact A. split. rewrite B; auto. intros; auto with asmgen.
+- (* floatconst *)
+ destruct (Float.eq_dec n Float.zero).
++ subst n. TranslOpSimpl.
++ TranslOpSimpl.
+- (* singleconst *)
+ destruct (Float32.eq_dec n Float32.zero).
++ subst n. TranslOpSimpl.
++ TranslOpSimpl.
+- (* loadsymbol *)
+ exploit (exec_loadsymbol x id ofs). eauto with asmgen. intros (rs' & A & B & C).
+ exists rs'; split. eexact A. split. rewrite B; auto. auto.
+- (* addrstack *)
+ exploit (exec_addimm64 x XSP (Ptrofs.to_int64 ofs)). simpl; eauto with asmgen.
+ intros (rs' & A & B & C).
+ exists rs'; split. eexact A. split. simpl in B; rewrite B.
+Local Transparent Val.addl.
+ destruct (rs SP); simpl; auto. rewrite Ptrofs.of_int64_to_int64 by auto. auto.
+ auto.
+- (* shift *)
+ rewrite <- transl_eval_shift'. TranslOpSimpl.
+- (* addimm *)
+ exploit (exec_addimm32 x x0 n). eauto with asmgen. intros (rs' & A & B & C).
+ exists rs'; split. eexact A. split. rewrite B; auto. auto.
+- (* mul *)
+ TranslOpBase.
+Local Transparent Val.add.
+ destruct (rs x0); auto; destruct (rs x1); auto. simpl. rewrite Int.add_zero_l; auto.
+- (* andimm *)
+ exploit (exec_logicalimm32 (Pandimm W) (Pand W)).
+ intros; reflexivity. intros; reflexivity. instantiate (1 := x0). eauto with asmgen.
+ intros (rs' & A & B & C).
+ exists rs'; split. eexact A. split. rewrite B; auto. auto.
+- (* orimm *)
+ exploit (exec_logicalimm32 (Porrimm W) (Porr W)).
+ intros; reflexivity. intros; reflexivity. instantiate (1 := x0). eauto with asmgen.
+ intros (rs' & A & B & C).
+ exists rs'; split. eexact A. split. rewrite B; auto. auto.
+- (* xorimm *)
+ exploit (exec_logicalimm32 (Peorimm W) (Peor W)).
+ intros; reflexivity. intros; reflexivity. instantiate (1 := x0). eauto with asmgen.
+ intros (rs' & A & B & C).
+ exists rs'; split. eexact A. split. rewrite B; auto. auto.
+- (* not *)
+ TranslOpBase.
+ destruct (rs x0); auto. simpl. rewrite Int.or_zero_l; auto.
+- (* notshift *)
+ TranslOpBase.
+ destruct (eval_shift s (rs x0) a); auto. simpl. rewrite Int.or_zero_l; auto.
+- (* shrx *)
+ exploit (exec_shrx32 x x0 n); eauto with asmgen. intros (rs' & A & B & C).
+ econstructor; split. eexact A. split. rewrite B; auto. auto.
+- (* zero-ext *)
+ TranslOpBase.
+ destruct (rs x0); auto; simpl. rewrite Int.shl_zero. auto.
+- (* sign-ext *)
+ TranslOpBase.
+ destruct (rs x0); auto; simpl. rewrite Int.shl_zero. auto.
+- (* shlzext *)
+ TranslOpBase.
+ destruct (rs x0); simpl; auto. rewrite <- Int.shl_zero_ext_min; auto using a32_range.
+- (* shlsext *)
+ TranslOpBase.
+ destruct (rs x0); simpl; auto. rewrite <- Int.shl_sign_ext_min; auto using a32_range.
+- (* zextshr *)
+ TranslOpBase.
+ destruct (rs x0); simpl; auto. rewrite ! a32_range; simpl. rewrite <- Int.zero_ext_shru_min; auto using a32_range.
+- (* sextshr *)
+ TranslOpBase.
+ destruct (rs x0); simpl; auto. rewrite ! a32_range; simpl. rewrite <- Int.sign_ext_shr_min; auto using a32_range.
+- (* shiftl *)
+ rewrite <- transl_eval_shiftl'. TranslOpSimpl.
+- (* extend *)
+ exploit (exec_move_extended x0 x1 x a k). intros (rs' & A & B & C).
+ econstructor; split. eexact A.
+ split. rewrite B; auto. eauto with asmgen.
+- (* addext *)
+ exploit (exec_arith_extended Val.addl Paddext (Padd X)).
+ auto. auto. instantiate (1 := x1). eauto with asmgen. intros (rs' & A & B & C).
+ econstructor; split. eexact A. split. rewrite B; auto. auto.
+- (* addlimm *)
+ exploit (exec_addimm64 x x0 n). simpl. generalize (ireg_of_not_X16 _ _ EQ1). congruence.
+ intros (rs' & A & B & C).
+ exists rs'; split. eexact A. split. simpl in B; rewrite B; auto. auto.
+- (* subext *)
+ exploit (exec_arith_extended Val.subl Psubext (Psub X)).
+ auto. auto. instantiate (1 := x1). eauto with asmgen. intros (rs' & A & B & C).
+ econstructor; split. eexact A. split. rewrite B; auto. auto.
+- (* mull *)
+ TranslOpBase.
+ destruct (rs x0); auto; destruct (rs x1); auto. simpl. rewrite Int64.add_zero_l; auto.
+- (* andlimm *)
+ exploit (exec_logicalimm64 (Pandimm X) (Pand X)).
+ intros; reflexivity. intros; reflexivity. instantiate (1 := x0). eauto with asmgen.
+ intros (rs' & A & B & C).
+ exists rs'; split. eexact A. split. rewrite B; auto. auto.
+- (* orlimm *)
+ exploit (exec_logicalimm64 (Porrimm X) (Porr X)).
+ intros; reflexivity. intros; reflexivity. instantiate (1 := x0). eauto with asmgen.
+ intros (rs' & A & B & C).
+ exists rs'; split. eexact A. split. rewrite B; auto. auto.
+- (* xorlimm *)
+ exploit (exec_logicalimm64 (Peorimm X) (Peor X)).
+ intros; reflexivity. intros; reflexivity. instantiate (1 := x0). eauto with asmgen.
+ intros (rs' & A & B & C).
+ exists rs'; split. eexact A. split. rewrite B; auto. auto.
+- (* notl *)
+ TranslOpBase.
+ destruct (rs x0); auto. simpl. rewrite Int64.or_zero_l; auto.
+- (* notlshift *)
+ TranslOpBase.
+ destruct (eval_shiftl s (rs x0) a); auto. simpl. rewrite Int64.or_zero_l; auto.
+- (* shrx *)
+ exploit (exec_shrx64 x x0 n); eauto with asmgen. intros (rs' & A & B & C).
+ econstructor; split. eexact A. split. rewrite B; auto. auto.
+- (* zero-ext-l *)
+ TranslOpBase.
+ destruct (rs x0); auto; simpl. rewrite Int64.shl'_zero. auto.
+- (* sign-ext-l *)
+ TranslOpBase.
+ destruct (rs x0); auto; simpl. rewrite Int64.shl'_zero. auto.
+- (* shllzext *)
+ TranslOpBase.
+ destruct (rs x0); simpl; auto. rewrite <- Int64.shl'_zero_ext_min; auto using a64_range.
+- (* shllsext *)
+ TranslOpBase.
+ destruct (rs x0); simpl; auto. rewrite <- Int64.shl'_sign_ext_min; auto using a64_range.
+- (* zextshrl *)
+ TranslOpBase.
+ destruct (rs x0); simpl; auto. rewrite ! a64_range; simpl. rewrite <- Int64.zero_ext_shru'_min; auto using a64_range.
+- (* sextshrl *)
+ TranslOpBase.
+ destruct (rs x0); simpl; auto. rewrite ! a64_range; simpl. rewrite <- Int64.sign_ext_shr'_min; auto using a64_range.
+- (* condition *)
+ exploit (transl_cond_correct cond args); eauto. intros (rs' & A & B & C).
+ econstructor; split.
+ eapply exec_straight_trans. eexact A. apply exec_straight_one. simpl; eauto. auto.
+ split. Simpl. destruct (eval_condition cond (map rs (map preg_of args)) m) as [b|]; simpl in *.
+ rewrite (B b) by auto. auto.
+ auto.
+ intros; Simpl.
+- (* select *)
+ destruct (preg_of res) eqn:RES; monadInv TR.
+ + (* integer *)
+ generalize (ireg_of_eq _ _ EQ) (ireg_of_eq _ _ EQ1); intros E1 E2; rewrite E1, E2.
+ exploit (transl_cond_correct cond args); eauto. intros (rs' & A & B & C).
+ econstructor; split.
+ eapply exec_straight_trans. eexact A. apply exec_straight_one. simpl; eauto. auto.
+ split. Simpl. destruct (eval_condition cond (map rs (map preg_of args)) m) as [b|]; simpl in *.
+ rewrite (B b) by auto. rewrite !C. apply Val.lessdef_normalize.
+ rewrite <- E2; auto with asmgen. rewrite <- E1; auto with asmgen.
+ auto.
+ intros; Simpl.
+ + (* FP *)
+ generalize (freg_of_eq _ _ EQ) (freg_of_eq _ _ EQ1); intros E1 E2; rewrite E1, E2.
+ exploit (transl_cond_correct cond args); eauto. intros (rs' & A & B & C).
+ econstructor; split.
+ eapply exec_straight_trans. eexact A. apply exec_straight_one. simpl; eauto. auto.
+ split. Simpl. destruct (eval_condition cond (map rs (map preg_of args)) m) as [b|]; simpl in *.
+ rewrite (B b) by auto. rewrite !C. apply Val.lessdef_normalize.
+ rewrite <- E2; auto with asmgen. rewrite <- E1; auto with asmgen.
+ auto.
+ intros; Simpl.
+Qed.
+
+(** Translation of addressing modes, loads, stores *)
+
+Lemma transl_addressing_correct:
+ forall sz addr args (insn: Asm.addressing -> instruction) k (rs: regset) m c b o,
+ transl_addressing sz addr args insn k = OK c ->
+ Op.eval_addressing ge (rs#SP) addr (map rs (map preg_of args)) = Some (Vptr b o) ->
+ exists ad rs',
+ exec_straight_opt ge fn c rs m (insn ad :: k) rs' m
+ /\ Asm.eval_addressing ge ad rs' = Vptr b o
+ /\ forall r, data_preg r = true -> rs' r = rs r.
+Proof.
+ intros until o; intros TR EV.
+ unfold transl_addressing in TR; destruct addr; ArgsInv; SimplEval EV.
+- (* Aindexed *)
+ destruct (offset_representable sz ofs); inv EQ0.
++ econstructor; econstructor; split. apply exec_straight_opt_refl.
+ auto.
++ exploit (exec_loadimm64 X16 ofs). intros (rs' & A & B & C).
+ econstructor; exists rs'; split. apply exec_straight_opt_intro; eexact A.
+ split. simpl. rewrite B, C by eauto with asmgen. auto.
+ eauto with asmgen.
+- (* Aindexed2 *)
+ econstructor; econstructor; split. apply exec_straight_opt_refl.
+ auto.
+- (* Aindexed2shift *)
+ destruct (Int.eq a Int.zero) eqn:E; [|destruct (Int.eq (Int.shl Int.one a) (Int.repr sz))]; inv EQ2.
++ apply Int.same_if_eq in E. rewrite E.
+ econstructor; econstructor; split. apply exec_straight_opt_refl.
+ split; auto. simpl.
+ rewrite Val.addl_commut in H0. destruct (rs x0); try discriminate.
+ unfold Val.shll. rewrite Int64.shl'_zero. auto.
++ econstructor; econstructor; split. apply exec_straight_opt_refl.
+ auto.
++ econstructor; econstructor; split.
+ apply exec_straight_opt_intro. apply exec_straight_one. simpl; eauto. auto.
+ split. simpl. Simpl. rewrite H0. simpl. rewrite Ptrofs.add_zero. auto.
+ intros; Simpl.
+- (* Aindexed2ext *)
+ destruct (Int.eq a Int.zero || Int.eq (Int.shl Int.one a) (Int.repr sz)); inv EQ2.
++ econstructor; econstructor; split. apply exec_straight_opt_refl.
+ split; auto. destruct x; auto.
++ exploit (exec_arith_extended Val.addl Paddext (Padd X)); auto.
+ instantiate (1 := x0). eauto with asmgen.
+ intros (rs' & A & B & C).
+ econstructor; exists rs'; split.
+ apply exec_straight_opt_intro. eexact A.
+ split. simpl. rewrite B. rewrite Val.addl_assoc. f_equal.
+ unfold Op.eval_extend; destruct x, (rs x1); simpl; auto; rewrite ! a64_range;
+ simpl; rewrite Int64.add_zero; auto.
+ intros. apply C; eauto with asmgen.
+- (* Aglobal *)
+ destruct (Ptrofs.eq (Ptrofs.modu ofs (Ptrofs.repr sz)) Ptrofs.zero); inv TR.
++ econstructor; econstructor; split.
+ apply exec_straight_opt_intro. apply exec_straight_one. simpl; eauto. auto.
+ split. simpl. Simpl. rewrite symbol_high_low. simpl in EV. congruence.
+ intros; Simpl.
++ exploit (exec_loadsymbol X16 id ofs). auto. intros (rs' & A & B & C).
+ econstructor; exists rs'; split.
+ apply exec_straight_opt_intro. eexact A.
+ split. simpl.
+ rewrite B. rewrite <- Genv.shift_symbol_address_64, Ptrofs.add_zero by auto.
+ simpl in EV. congruence.
+ auto with asmgen.
+- (* Ainstrack *)
+ assert (E: Val.addl (rs SP) (Vlong (Ptrofs.to_int64 ofs)) = Vptr b o).
+ { simpl in EV. inv EV. destruct (rs SP); simpl in H1; inv H1. simpl.
+ rewrite Ptrofs.of_int64_to_int64 by auto. auto. }
+ destruct (offset_representable sz (Ptrofs.to_int64 ofs)); inv TR.
++ econstructor; econstructor; split. apply exec_straight_opt_refl.
+ auto.
++ exploit (exec_loadimm64 X16 (Ptrofs.to_int64 ofs)). intros (rs' & A & B & C).
+ econstructor; exists rs'; split.
+ apply exec_straight_opt_intro. eexact A.
+ split. simpl. rewrite B, C by eauto with asmgen. auto.
+ auto with asmgen.
+Qed.
+
+Lemma transl_load_correct:
+ forall chunk addr args dst k c (rs: regset) m vaddr v,
+ transl_load chunk addr args dst k = OK c ->
+ Op.eval_addressing ge (rs#SP) addr (map rs (map preg_of args)) = Some vaddr ->
+ Mem.loadv chunk m vaddr = Some v ->
+ exists rs',
+ exec_straight ge fn c rs m k rs' m
+ /\ rs'#(preg_of dst) = v
+ /\ forall r, data_preg r = true -> r <> preg_of dst -> rs' r = rs r.
+Proof.
+ intros. destruct vaddr; try discriminate.
+ assert (A: exists sz insn,
+ transl_addressing sz addr args insn k = OK c
+ /\ (forall ad rs', exec_instr ge fn (insn ad) rs' m =
+ exec_load ge chunk (fun v => v) ad (preg_of dst) rs' m)).
+ {
+ destruct chunk; monadInv H;
+ try rewrite (ireg_of_eq _ _ EQ); try rewrite (freg_of_eq _ _ EQ);
+ do 2 econstructor; (split; [eassumption|auto]).
+ }
+ destruct A as (sz & insn & B & C).
+ exploit transl_addressing_correct. eexact B. eexact H0. intros (ad & rs' & P & Q & R).
+ assert (X: exec_load ge chunk (fun v => v) ad (preg_of dst) rs' m =
+ Next (nextinstr (rs'#(preg_of dst) <- v)) m).
+ { unfold exec_load. rewrite Q, H1. auto. }
+ econstructor; split.
+ eapply exec_straight_opt_right. eexact P.
+ apply exec_straight_one. rewrite C, X; eauto. Simpl.
+ split. Simpl. intros; Simpl.
+Qed.
+
+Lemma transl_store_correct:
+ forall chunk addr args src k c (rs: regset) m vaddr m',
+ transl_store chunk addr args src k = OK c ->
+ Op.eval_addressing ge (rs#SP) addr (map rs (map preg_of args)) = Some vaddr ->
+ Mem.storev chunk m vaddr rs#(preg_of src) = Some m' ->
+ exists rs',
+ exec_straight ge fn c rs m k rs' m'
+ /\ forall r, data_preg r = true -> rs' r = rs r.
+Proof.
+ intros. destruct vaddr; try discriminate.
+ set (chunk' := match chunk with Mint8signed => Mint8unsigned
+ | Mint16signed => Mint16unsigned
+ | _ => chunk end).
+ assert (A: exists sz insn,
+ transl_addressing sz addr args insn k = OK c
+ /\ (forall ad rs', exec_instr ge fn (insn ad) rs' m =
+ exec_store ge chunk' ad rs'#(preg_of src) rs' m)).
+ {
+ unfold chunk'; destruct chunk; monadInv H;
+ try rewrite (ireg_of_eq _ _ EQ); try rewrite (freg_of_eq _ _ EQ);
+ do 2 econstructor; (split; [eassumption|auto]).
+ }
+ destruct A as (sz & insn & B & C).
+ exploit transl_addressing_correct. eexact B. eexact H0. intros (ad & rs' & P & Q & R).
+ assert (X: Mem.storev chunk' m (Vptr b i) rs#(preg_of src) = Some m').
+ { rewrite <- H1. unfold chunk'. destruct chunk; auto; simpl; symmetry.
+ apply Mem.store_signed_unsigned_8.
+ apply Mem.store_signed_unsigned_16. }
+ assert (Y: exec_store ge chunk' ad rs'#(preg_of src) rs' m =
+ Next (nextinstr rs') m').
+ { unfold exec_store. rewrite Q, R, X by auto with asmgen. auto. }
+ econstructor; split.
+ eapply exec_straight_opt_right. eexact P.
+ apply exec_straight_one. rewrite C, Y; eauto. Simpl.
+ intros; Simpl.
+Qed.
+
+(** Translation of indexed memory accesses *)
+
+Lemma indexed_memory_access_correct: forall insn sz (base: iregsp) ofs k (rs: regset) m b i,
+ preg_of_iregsp base <> IR X16 ->
+ Val.offset_ptr rs#base ofs = Vptr b i ->
+ exists ad rs',
+ exec_straight_opt ge fn (indexed_memory_access insn sz base ofs k) rs m (insn ad :: k) rs' m
+ /\ Asm.eval_addressing ge ad rs' = Vptr b i
+ /\ forall r, r <> PC -> r <> X16 -> rs' r = rs r.
+Proof.
+ unfold indexed_memory_access; intros.
+ assert (Val.addl rs#base (Vlong (Ptrofs.to_int64 ofs)) = Vptr b i).
+ { destruct (rs base); try discriminate. simpl in *. rewrite Ptrofs.of_int64_to_int64 by auto. auto. }
+ destruct offset_representable.
+- econstructor; econstructor; split. apply exec_straight_opt_refl. auto.
+- exploit (exec_loadimm64 X16); eauto. intros (rs' & A & B & C).
+ econstructor; econstructor; split. apply exec_straight_opt_intro; eexact A.
+ split. simpl. rewrite B, C by eauto with asmgen. auto. auto.
+Qed.
+
+Lemma loadptr_correct: forall (base: iregsp) ofs dst k m v (rs: regset),
+ Mem.loadv Mint64 m (Val.offset_ptr rs#base ofs) = Some v ->
+ preg_of_iregsp base <> IR X16 ->
+ exists rs',
+ exec_straight ge fn (loadptr base ofs dst k) rs m k rs' m
+ /\ rs'#dst = v
+ /\ forall r, r <> PC -> r <> X16 -> r <> dst -> rs' r = rs r.
+Proof.
+ intros.
+ destruct (Val.offset_ptr rs#base ofs) eqn:V; try discriminate.
+ exploit indexed_memory_access_correct; eauto. intros (ad & rs' & A & B & C).
+ econstructor; split.
+ eapply exec_straight_opt_right. eexact A.
+ apply exec_straight_one. simpl. unfold exec_load. rewrite B, H. eauto. auto.
+ split. Simpl. intros; Simpl.
+Qed.
+
+Lemma storeptr_correct: forall (base: iregsp) ofs (src: ireg) k m m' (rs: regset),
+ Mem.storev Mint64 m (Val.offset_ptr rs#base ofs) rs#src = Some m' ->
+ preg_of_iregsp base <> IR X16 ->
+ src <> X16 ->
+ exists rs',
+ exec_straight ge fn (storeptr src base ofs k) rs m k rs' m'
+ /\ forall r, r <> PC -> r <> X16 -> rs' r = rs r.
+Proof.
+ intros.
+ destruct (Val.offset_ptr rs#base ofs) eqn:V; try discriminate.
+ exploit indexed_memory_access_correct; eauto. intros (ad & rs' & A & B & C).
+ econstructor; split.
+ eapply exec_straight_opt_right. eexact A.
+ apply exec_straight_one. simpl. unfold exec_store. rewrite B, C, H by eauto with asmgen. eauto. auto.
+ intros; Simpl.
+Qed.
+
+Lemma loadind_correct: forall (base: iregsp) ofs ty dst k c (rs: regset) m v,
+ loadind base ofs ty dst k = OK c ->
+ Mem.loadv (chunk_of_type ty) m (Val.offset_ptr rs#base ofs) = Some v ->
+ preg_of_iregsp base <> IR X16 ->
+ exists rs',
+ exec_straight ge fn c rs m k rs' m
+ /\ rs'#(preg_of dst) = v
+ /\ forall r, data_preg r = true -> r <> preg_of dst -> rs' r = rs r.
+Proof.
+ intros.
+ destruct (Val.offset_ptr rs#base ofs) eqn:V; try discriminate.
+ assert (X: exists sz insn,
+ c = indexed_memory_access insn sz base ofs k
+ /\ (forall ad rs', exec_instr ge fn (insn ad) rs' m =
+ exec_load ge (chunk_of_type ty) (fun v => v) ad (preg_of dst) rs' m)).
+ {
+ unfold loadind in H; destruct ty; destruct (preg_of dst); inv H; do 2 econstructor; eauto.
+ }
+ destruct X as (sz & insn & EQ & SEM). subst c.
+ exploit indexed_memory_access_correct; eauto. intros (ad & rs' & A & B & C).
+ econstructor; split.
+ eapply exec_straight_opt_right. eexact A.
+ apply exec_straight_one. rewrite SEM. unfold exec_load. rewrite B, H0. eauto. Simpl.
+ split. Simpl. intros; Simpl.
+Qed.
+
+Lemma storeind_correct: forall (base: iregsp) ofs ty src k c (rs: regset) m m',
+ storeind src base ofs ty k = OK c ->
+ Mem.storev (chunk_of_type ty) m (Val.offset_ptr rs#base ofs) rs#(preg_of src) = Some m' ->
+ preg_of_iregsp base <> IR X16 ->
+ exists rs',
+ exec_straight ge fn c rs m k rs' m'
+ /\ forall r, data_preg r = true -> rs' r = rs r.
+Proof.
+ intros.
+ destruct (Val.offset_ptr rs#base ofs) eqn:V; try discriminate.
+ assert (X: exists sz insn,
+ c = indexed_memory_access insn sz base ofs k
+ /\ (forall ad rs', exec_instr ge fn (insn ad) rs' m =
+ exec_store ge (chunk_of_type ty) ad rs'#(preg_of src) rs' m)).
+ {
+ unfold storeind in H; destruct ty; destruct (preg_of src); inv H; do 2 econstructor; eauto.
+ }
+ destruct X as (sz & insn & EQ & SEM). subst c.
+ exploit indexed_memory_access_correct; eauto. intros (ad & rs' & A & B & C).
+ econstructor; split.
+ eapply exec_straight_opt_right. eexact A.
+ apply exec_straight_one. rewrite SEM.
+ unfold exec_store. rewrite B, C, H0 by eauto with asmgen. eauto.
+ Simpl.
+ intros; Simpl.
+Qed.
+
+Lemma make_epilogue_correct:
+ forall ge0 f m stk soff cs m' ms rs k tm,
+ load_stack m (Vptr stk soff) Tptr f.(fn_link_ofs) = Some (parent_sp cs) ->
+ load_stack m (Vptr stk soff) Tptr f.(fn_retaddr_ofs) = Some (parent_ra cs) ->
+ Mem.free m stk 0 f.(fn_stacksize) = Some m' ->
+ agree ms (Vptr stk soff) rs ->
+ Mem.extends m tm ->
+ match_stack ge0 cs ->
+ exists rs', exists tm',
+ exec_straight ge fn (make_epilogue f k) rs tm k rs' tm'
+ /\ agree ms (parent_sp cs) rs'
+ /\ Mem.extends m' tm'
+ /\ rs'#RA = parent_ra cs
+ /\ rs'#SP = parent_sp cs
+ /\ (forall r, r <> PC -> r <> SP -> r <> X30 -> r <> X16 -> rs'#r = rs#r).
+Proof.
+ intros until tm; intros LP LRA FREE AG MEXT MCS.
+ exploit Mem.loadv_extends. eauto. eexact LP. auto. simpl. intros (parent' & LP' & LDP').
+ exploit Mem.loadv_extends. eauto. eexact LRA. auto. simpl. intros (ra' & LRA' & LDRA').
+ exploit lessdef_parent_sp; eauto. intros EQ; subst parent'; clear LDP'.
+ exploit lessdef_parent_ra; eauto. intros EQ; subst ra'; clear LDRA'.
+ exploit Mem.free_parallel_extends; eauto. intros (tm' & FREE' & MEXT').
+ unfold make_epilogue.
+ exploit (loadptr_correct XSP (fn_retaddr_ofs f)).
+ instantiate (2 := rs). simpl. rewrite <- (sp_val _ _ _ AG). simpl. eexact LRA'. simpl; congruence.
+ intros (rs1 & A1 & B1 & C1).
+ econstructor; econstructor; split.
+ eapply exec_straight_trans. eexact A1. apply exec_straight_one. simpl.
+ simpl; rewrite (C1 SP) by auto with asmgen. rewrite <- (sp_val _ _ _ AG). simpl; rewrite LP'.
+ rewrite FREE'. eauto. auto.
+ split. apply agree_nextinstr. apply agree_set_other; auto.
+ apply agree_change_sp with (Vptr stk soff).
+ apply agree_exten with rs; auto. intros; apply C1; auto with asmgen.
+ eapply parent_sp_def; eauto.
+ split. auto.
+ split. Simpl.
+ split. Simpl.
+ intros. Simpl.
+Qed.
+
+End CONSTRUCTORS.
diff --git a/aarch64/Builtins1.v b/aarch64/Builtins1.v
new file mode 100644
index 00000000..f6e643d2
--- /dev/null
+++ b/aarch64/Builtins1.v
@@ -0,0 +1,33 @@
+(* *********************************************************************)
+(* *)
+(* 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 GNU General Public License as published by *)
+(* the Free Software Foundation, either version 2 of the License, or *)
+(* (at your option) any later version. This file is also distributed *)
+(* under the terms of the INRIA Non-Commercial License Agreement. *)
+(* *)
+(* *********************************************************************)
+
+(** Platform-specific built-in functions *)
+
+Require Import String Coqlib.
+Require Import AST Integers Floats Values.
+Require Import Builtins0.
+
+Inductive platform_builtin : Type := .
+
+Local Open Scope string_scope.
+
+Definition platform_builtin_table : list (string * platform_builtin) :=
+ nil.
+
+Definition platform_builtin_sig (b: platform_builtin) : signature :=
+ match b with end.
+
+Definition platform_builtin_sem (b: platform_builtin) : builtin_sem (proj_sig_res (platform_builtin_sig b)) :=
+ match b with end.
diff --git a/aarch64/CBuiltins.ml b/aarch64/CBuiltins.ml
new file mode 100644
index 00000000..fdc1372d
--- /dev/null
+++ b/aarch64/CBuiltins.ml
@@ -0,0 +1,72 @@
+(* *********************************************************************)
+(* *)
+(* 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. *)
+(* *)
+(* *********************************************************************)
+
+(* Processor-dependent builtin C functions *)
+
+open C
+
+(* va_list is a struct of size 32 and alignment 8, passed by reference *)
+
+let va_list_type = TArray(TInt(IULong, []), Some 4L, [])
+let size_va_list = 32
+let va_list_scalar = false
+
+let builtins = {
+ builtin_typedefs = [
+ "__builtin_va_list", va_list_type
+ ];
+ builtin_functions = [
+ (* Synchronization *)
+ "__builtin_fence",
+ (TVoid [], [], false);
+ (* Integer arithmetic *)
+ "__builtin_bswap64",
+ (TInt(IULongLong, []), [TInt(IULongLong, [])], false);
+ "__builtin_clz",
+ (TInt(IInt, []), [TInt(IUInt, [])], false);
+ "__builtin_clzl",
+ (TInt(IInt, []), [TInt(IULong, [])], false);
+ "__builtin_clzll",
+ (TInt(IInt, []), [TInt(IULongLong, [])], false);
+ "__builtin_cls",
+ (TInt(IInt, []), [TInt(IInt, [])], false);
+ "__builtin_clsl",
+ (TInt(IInt, []), [TInt(ILong, [])], false);
+ "__builtin_clsll",
+ (TInt(IInt, []), [TInt(ILongLong, [])], false);
+ (* Float arithmetic *)
+ "__builtin_fmadd",
+ (TFloat(FDouble, []),
+ [TFloat(FDouble, []); TFloat(FDouble, []); TFloat(FDouble, [])],
+ false);
+ "__builtin_fmsub",
+ (TFloat(FDouble, []),
+ [TFloat(FDouble, []); TFloat(FDouble, []); TFloat(FDouble, [])],
+ false);
+ "__builtin_fnmadd",
+ (TFloat(FDouble, []),
+ [TFloat(FDouble, []); TFloat(FDouble, []); TFloat(FDouble, [])],
+ false);
+ "__builtin_fnmsub",
+ (TFloat(FDouble, []),
+ [TFloat(FDouble, []); TFloat(FDouble, []); TFloat(FDouble, [])],
+ false);
+ "__builtin_fmax",
+ (TFloat(FDouble, []), [TFloat(FDouble, []); TFloat(FDouble, [])], false);
+ "__builtin_fmin",
+ (TFloat(FDouble, []), [TFloat(FDouble, []); TFloat(FDouble, [])], false);
+ ]
+}
+
+(* Expand memory references inside extended asm statements. Used in C2C. *)
+
+let asm_mem_argument arg = Printf.sprintf "[%s]" arg
diff --git a/aarch64/CombineOp.v b/aarch64/CombineOp.v
new file mode 100644
index 00000000..4d78c9a0
--- /dev/null
+++ b/aarch64/CombineOp.v
@@ -0,0 +1,137 @@
+(* *********************************************************************)
+(* *)
+(* 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. *)
+(* *)
+(* *********************************************************************)
+
+(** Recognition of combined operations, addressing modes and conditions
+ during the [CSE] phase. *)
+
+Require Import Coqlib.
+Require Import AST Integers.
+Require Import Op.
+Require Import CSEdomain.
+
+Section COMBINE.
+
+Variable get: valnum -> option rhs.
+
+Function combine_compimm_ne_0 (x: valnum) : option(condition * list valnum) :=
+ match get x with
+ | Some(Op (Ocmp c) ys) => Some (c, ys)
+ | _ => None
+ end.
+
+Function combine_compimm_eq_0 (x: valnum) : option(condition * list valnum) :=
+ match get x with
+ | Some(Op (Ocmp c) ys) => Some (negate_condition c, ys)
+ | _ => None
+ end.
+
+Function combine_compimm_eq_1 (x: valnum) : option(condition * list valnum) :=
+ match get x with
+ | Some(Op (Ocmp c) ys) => Some (c, ys)
+ | _ => None
+ end.
+
+Function combine_compimm_ne_1 (x: valnum) : option(condition * list valnum) :=
+ match get x with
+ | Some(Op (Ocmp c) ys) => Some (negate_condition c, ys)
+ | _ => None
+ end.
+
+Function combine_cond (cond: condition) (args: list valnum) : option(condition * list valnum) :=
+ match cond, args with
+ | Ccompimm Cne n, x::nil =>
+ if Int.eq_dec n Int.zero then combine_compimm_ne_0 x
+ else if Int.eq_dec n Int.one then combine_compimm_ne_1 x
+ else None
+ | Ccompimm Ceq n, x::nil =>
+ if Int.eq_dec n Int.zero then combine_compimm_eq_0 x
+ else if Int.eq_dec n Int.one then combine_compimm_eq_1 x
+ else None
+ | Ccompuimm Cne n, x::nil =>
+ if Int.eq_dec n Int.zero then combine_compimm_ne_0 x
+ else if Int.eq_dec n Int.one then combine_compimm_ne_1 x
+ else None
+ | Ccompuimm Ceq n, x::nil =>
+ if Int.eq_dec n Int.zero then combine_compimm_eq_0 x
+ else if Int.eq_dec n Int.one then combine_compimm_eq_1 x
+ else None
+ | _, _ => None
+ end.
+
+Function combine_addr (addr: addressing) (args: list valnum) : option(addressing * list valnum) :=
+ match addr, args with
+ | Aindexed n, x::nil =>
+ match get x with
+ | Some(Op (Oaddlimm m) ys) =>
+ Some(Aindexed (Int64.add m n), ys)
+ | _ => None
+ end
+ | _, _ => None
+ end.
+
+Function combine_op (op: operation) (args: list valnum) : option(operation * list valnum) :=
+ match op, args with
+ | Oaddimm n, x :: nil =>
+ match get x with
+ | Some(Op (Oaddimm m) ys) => Some(Oaddimm (Int.add m n), ys)
+ | _ => None
+ end
+ | Oandimm n, x :: nil =>
+ match get x with
+ | Some(Op (Oandimm m) ys) =>
+ Some(let p := Int.and m n in
+ if Int.eq p m then (Omove, x :: nil) else (Oandimm p, ys))
+ | _ => None
+ end
+ | Oorimm n, x :: nil =>
+ match get x with
+ | Some(Op (Oorimm m) ys) => Some(Oorimm (Int.or m n), ys)
+ | _ => None
+ end
+ | Oxorimm n, x :: nil =>
+ match get x with
+ | Some(Op (Oxorimm m) ys) => Some(Oxorimm (Int.xor m n), ys)
+ | _ => None
+ end
+ | Oaddlimm n, x :: nil =>
+ match get x with
+ | Some(Op (Oaddlimm m) ys) => Some(Oaddlimm (Int64.add m n), ys)
+ | _ => None
+ end
+ | Oandlimm n, x :: nil =>
+ match get x with
+ | Some(Op (Oandlimm m) ys) =>
+ Some(let p := Int64.and m n in
+ if Int64.eq p m then (Omove, x :: nil) else (Oandlimm p, ys))
+ | _ => None
+ end
+ | Oorlimm n, x :: nil =>
+ match get x with
+ | Some(Op (Oorlimm m) ys) => Some(Oorlimm (Int64.or m n), ys)
+ | _ => None
+ end
+ | Oxorlimm n, x :: nil =>
+ match get x with
+ | Some(Op (Oxorlimm m) ys) => Some(Oxorlimm (Int64.xor m n), ys)
+ | _ => None
+ end
+ | Ocmp cond, _ =>
+ match combine_cond cond args with
+ | Some(cond', args') => Some(Ocmp cond', args')
+ | None => None
+ end
+ | _, _ => None
+ end.
+
+End COMBINE.
+
+
diff --git a/aarch64/CombineOpproof.v b/aarch64/CombineOpproof.v
new file mode 100644
index 00000000..7d13b964
--- /dev/null
+++ b/aarch64/CombineOpproof.v
@@ -0,0 +1,161 @@
+(* *********************************************************************)
+(* *)
+(* 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. *)
+(* *)
+(* *********************************************************************)
+
+Require Import FunInd.
+Require Import Coqlib.
+Require Import AST Integers Values Memory.
+Require Import Op Registers RTL.
+Require Import CSEdomain.
+Require Import CombineOp.
+
+Section COMBINE.
+
+Variable ge: genv.
+Variable sp: val.
+Variable m: mem.
+Variable get: valnum -> option rhs.
+Variable valu: valnum -> val.
+Hypothesis get_sound: forall v rhs, get v = Some rhs -> rhs_eval_to valu ge sp m rhs (valu v).
+
+Lemma get_op_sound:
+ forall v op vl, get v = Some (Op op vl) -> eval_operation ge sp op (map valu vl) m = Some (valu v).
+Proof.
+ intros. exploit get_sound; eauto. intros REV; inv REV; auto.
+Qed.
+
+Ltac UseGetSound :=
+ match goal with
+ | [ H: get _ = Some _ |- _ ] =>
+ let x := fresh "EQ" in (generalize (get_op_sound _ _ _ H); intros x; simpl in x; FuncInv)
+ end.
+
+Lemma combine_compimm_ne_0_sound:
+ forall x cond args,
+ combine_compimm_ne_0 get x = Some(cond, args) ->
+ eval_condition cond (map valu args) m = Val.cmp_bool Cne (valu x) (Vint Int.zero) /\
+ eval_condition cond (map valu args) m = Val.cmpu_bool (Mem.valid_pointer m) Cne (valu x) (Vint Int.zero).
+Proof.
+ intros until args. functional induction (combine_compimm_ne_0 get x); intros EQ; inv EQ.
+ (* of cmp *)
+ UseGetSound. rewrite <- H.
+ destruct (eval_condition cond (map valu args) m); simpl; auto. destruct b; auto.
+Qed.
+
+Lemma combine_compimm_eq_0_sound:
+ forall x cond args,
+ combine_compimm_eq_0 get x = Some(cond, args) ->
+ eval_condition cond (map valu args) m = Val.cmp_bool Ceq (valu x) (Vint Int.zero) /\
+ eval_condition cond (map valu args) m = Val.cmpu_bool (Mem.valid_pointer m) Ceq (valu x) (Vint Int.zero).
+Proof.
+ intros until args. functional induction (combine_compimm_eq_0 get x); intros EQ; inv EQ.
+ (* of cmp *)
+ UseGetSound. rewrite <- H.
+ rewrite eval_negate_condition.
+ destruct (eval_condition c (map valu args) m); simpl; auto. destruct b; auto.
+Qed.
+
+Lemma combine_compimm_eq_1_sound:
+ forall x cond args,
+ combine_compimm_eq_1 get x = Some(cond, args) ->
+ eval_condition cond (map valu args) m = Val.cmp_bool Ceq (valu x) (Vint Int.one) /\
+ eval_condition cond (map valu args) m = Val.cmpu_bool (Mem.valid_pointer m) Ceq (valu x) (Vint Int.one).
+Proof.
+ intros until args. functional induction (combine_compimm_eq_1 get x); intros EQ; inv EQ.
+ (* of cmp *)
+ UseGetSound. rewrite <- H.
+ destruct (eval_condition cond (map valu args) m); simpl; auto. destruct b; auto.
+Qed.
+
+Lemma combine_compimm_ne_1_sound:
+ forall x cond args,
+ combine_compimm_ne_1 get x = Some(cond, args) ->
+ eval_condition cond (map valu args) m = Val.cmp_bool Cne (valu x) (Vint Int.one) /\
+ eval_condition cond (map valu args) m = Val.cmpu_bool (Mem.valid_pointer m) Cne (valu x) (Vint Int.one).
+Proof.
+ intros until args. functional induction (combine_compimm_ne_1 get x); intros EQ; inv EQ.
+ (* of cmp *)
+ UseGetSound. rewrite <- H.
+ rewrite eval_negate_condition.
+ destruct (eval_condition c (map valu args) m); simpl; auto. destruct b; auto.
+Qed.
+
+Theorem combine_cond_sound:
+ forall cond args cond' args',
+ combine_cond get cond args = Some(cond', args') ->
+ eval_condition cond' (map valu args') m = eval_condition cond (map valu args) m.
+Proof.
+ intros. functional inversion H; subst.
+ (* compimm ne zero *)
+ - simpl; eapply combine_compimm_ne_0_sound; eauto.
+ (* compimm ne one *)
+ - simpl; eapply combine_compimm_ne_1_sound; eauto.
+ (* compimm eq zero *)
+ - simpl; eapply combine_compimm_eq_0_sound; eauto.
+ (* compimm eq one *)
+ - simpl; eapply combine_compimm_eq_1_sound; eauto.
+ (* compuimm ne zero *)
+ - simpl; eapply combine_compimm_ne_0_sound; eauto.
+ (* compuimm ne one *)
+ - simpl; eapply combine_compimm_ne_1_sound; eauto.
+ (* compuimm eq zero *)
+ - simpl; eapply combine_compimm_eq_0_sound; eauto.
+ (* compuimm eq one *)
+ - simpl; eapply combine_compimm_eq_1_sound; eauto.
+Qed.
+
+Theorem combine_addr_sound:
+ forall addr args addr' args',
+ combine_addr get addr args = Some(addr', args') ->
+ eval_addressing ge sp addr' (map valu args') = eval_addressing ge sp addr (map valu args).
+Proof.
+ intros. functional inversion H; subst.
+- (* indexed - addimml *)
+ UseGetSound. simpl. rewrite <- H0. rewrite Val.addl_assoc. auto.
+Qed.
+
+Theorem combine_op_sound:
+ forall op args op' args',
+ combine_op get op args = Some(op', args') ->
+ eval_operation ge sp op' (map valu args') m = eval_operation ge sp op (map valu args) m.
+Proof.
+ intros. functional inversion H; subst.
+ (* addimm - addimm *)
+ - UseGetSound. FuncInv. simpl.
+ rewrite <- H0. rewrite Val.add_assoc. auto.
+ (* andimm - andimm *)
+ - UseGetSound; simpl.
+ generalize (Int.eq_spec p m0); rewrite H7; intros.
+ rewrite <- H0. rewrite Val.and_assoc. simpl. fold p. rewrite H1. auto.
+ - UseGetSound; simpl.
+ rewrite <- H0. rewrite Val.and_assoc. auto.
+ (* orimm - orimm *)
+ - UseGetSound. simpl. rewrite <- H0. rewrite Val.or_assoc. auto.
+ (* xorimm - xorimm *)
+ - UseGetSound. simpl. rewrite <- H0. rewrite Val.xor_assoc. auto.
+ (* addlimm - addlimm *)
+ - UseGetSound. FuncInv. simpl.
+ rewrite <- H0. rewrite Val.addl_assoc. auto.
+ (* andlimm - andlimm *)
+ - UseGetSound; simpl.
+ generalize (Int64.eq_spec p m0); rewrite H7; intros.
+ rewrite <- H0. rewrite Val.andl_assoc. simpl. fold p. rewrite H1. auto.
+ - UseGetSound; simpl.
+ rewrite <- H0. rewrite Val.andl_assoc. auto.
+ (* orlimm - orlimm *)
+ - UseGetSound. simpl. rewrite <- H0. rewrite Val.orl_assoc. auto.
+ (* xorlimm - xorlimm *)
+ - UseGetSound. simpl. rewrite <- H0. rewrite Val.xorl_assoc. auto.
+ (* cmp *)
+ - simpl. decEq; decEq. eapply combine_cond_sound; eauto.
+Qed.
+
+End COMBINE.
diff --git a/aarch64/ConstpropOp.vp b/aarch64/ConstpropOp.vp
new file mode 100644
index 00000000..c0a2c6bf
--- /dev/null
+++ b/aarch64/ConstpropOp.vp
@@ -0,0 +1,401 @@
+(* *********************************************************************)
+(* *)
+(* 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. *)
+(* *)
+(* *********************************************************************)
+
+(** Strength reduction for operators and conditions.
+ This is the machine-dependent part of [Constprop]. *)
+
+Require Archi.
+Require Import Coqlib Compopts.
+Require Import AST Integers Floats.
+Require Import Op Registers.
+Require Import ValueDomain ValueAOp.
+
+(** * Converting known values to constants *)
+
+Definition const_for_result (a: aval) : option operation :=
+ match a with
+ | I n => Some(Ointconst n)
+ | L n => Some(Olongconst n)
+ | F n => if Compopts.generate_float_constants tt then Some(Ofloatconst n) else None
+ | FS n => if Compopts.generate_float_constants tt then Some(Osingleconst n) else None
+ | Ptr(Gl id ofs) => Some(Oaddrsymbol id ofs)
+ | Ptr(Stk ofs) => Some(Oaddrstack ofs)
+ | _ => None
+ end.
+
+(** * Operator strength reduction *)
+
+Definition eval_static_shift (s: shift) (v: int) (n: amount32) : int :=
+ match s with
+ | Slsl => Int.shl v n
+ | Slsr => Int.shru v n
+ | Sasr => Int.shr v n
+ | Sror => Int.ror v n
+ end.
+
+Definition eval_static_shiftl (s: shift) (v: int64) (n: amount64) : int64 :=
+ match s with
+ | Slsl => Int64.shl' v n
+ | Slsr => Int64.shru' v n
+ | Sasr => Int64.shr' v n
+ | Sror => Int64.ror v (Int64.repr (Int.unsigned n))
+ end.
+
+Definition eval_static_extend (x: extension) (v: int) (n: amount64) : int64 :=
+ Int64.shl' (match x with Xsgn32 => Int64.repr (Int.signed v)
+ | Xuns32 => Int64.repr (Int.unsigned v) end)
+ n.
+
+Nondetfunction cond_strength_reduction
+ (cond: condition) (args: list reg) (vl: list aval) :=
+ match cond, args, vl with
+ | Ccomp c, r1 :: r2 :: nil, I n1 :: v2 :: nil =>
+ (Ccompimm (swap_comparison c) n1, r2 :: nil)
+ | Ccomp c, r1 :: r2 :: nil, v1 :: I n2 :: nil =>
+ (Ccompimm c n2, r1 :: nil)
+ | Ccompu c, r1 :: r2 :: nil, I n1 :: v2 :: nil =>
+ (Ccompuimm (swap_comparison c) n1, r2 :: nil)
+ | Ccompu c, r1 :: r2 :: nil, v1 :: I n2 :: nil =>
+ (Ccompuimm c n2, r1 :: nil)
+ | Ccompshift c s a, r1 :: r2 :: nil, v1 :: I n2 :: nil =>
+ (Ccompimm c (eval_static_shift s n2 a), r1 :: nil)
+ | Ccompushift c s a, r1 :: r2 :: nil, v1 :: I n2 :: nil =>
+ (Ccompuimm c (eval_static_shift s n2 a), r1 :: nil)
+ | Ccompl c, r1 :: r2 :: nil, L n1 :: v2 :: nil =>
+ (Ccomplimm (swap_comparison c) n1, r2 :: nil)
+ | Ccompl c, r1 :: r2 :: nil, v1 :: L n2 :: nil =>
+ (Ccomplimm c n2, r1 :: nil)
+ | Ccomplu c, r1 :: r2 :: nil, L n1 :: v2 :: nil =>
+ (Ccompluimm (swap_comparison c) n1, r2 :: nil)
+ | Ccomplu c, r1 :: r2 :: nil, v1 :: L n2 :: nil =>
+ (Ccompluimm c n2, r1 :: nil)
+ | Ccomplshift c s a, r1 :: r2 :: nil, v1 :: L n2 :: nil =>
+ (Ccomplimm c (eval_static_shiftl s n2 a), r1 :: nil)
+ | Ccomplushift c s a, r1 :: r2 :: nil, v1 :: L n2 :: nil =>
+ (Ccompluimm c (eval_static_shiftl s n2 a), r1 :: nil)
+ | Ccompf c, r1 :: r2 :: nil, F n1 :: v2 :: nil =>
+ if Float.eq_dec n1 Float.zero
+ then (Ccompfzero (swap_comparison c), r2 :: nil)
+ else (cond, args)
+ | Ccompf c, r1 :: r2 :: nil, v1 :: F n2 :: nil =>
+ if Float.eq_dec n2 Float.zero
+ then (Ccompfzero c, r1 :: nil)
+ else (cond, args)
+ | Cnotcompf c, r1 :: r2 :: nil, F n1 :: v2 :: nil =>
+ if Float.eq_dec n1 Float.zero
+ then (Cnotcompfzero (swap_comparison c), r2 :: nil)
+ else (cond, args)
+ | Cnotcompf c, r1 :: r2 :: nil, v1 :: F n2 :: nil =>
+ if Float.eq_dec n2 Float.zero
+ then (Cnotcompfzero c, r1 :: nil)
+ else (cond, args)
+ | Ccompfs c, r1 :: r2 :: nil, FS n1 :: v2 :: nil =>
+ if Float32.eq_dec n1 Float32.zero
+ then (Ccompfszero (swap_comparison c), r2 :: nil)
+ else (cond, args)
+ | Ccompfs c, r1 :: r2 :: nil, v1 :: FS n2 :: nil =>
+ if Float32.eq_dec n2 Float32.zero
+ then (Ccompfszero c, r1 :: nil)
+ else (cond, args)
+ | Cnotcompfs c, r1 :: r2 :: nil, FS n1 :: v2 :: nil =>
+ if Float32.eq_dec n1 Float32.zero
+ then (Cnotcompfszero (swap_comparison c), r2 :: nil)
+ else (cond, args)
+ | Cnotcompfs c, r1 :: r2 :: nil, v1 :: FS n2 :: nil =>
+ if Float32.eq_dec n2 Float32.zero
+ then (Cnotcompfszero c, r1 :: nil)
+ else (cond, args)
+ | _, _, _ =>
+ (cond, args)
+ end.
+
+Definition make_cmp_base (c: condition) (args: list reg) (vl: list aval) :=
+ let (c', args') := cond_strength_reduction c args vl in (Ocmp c', args').
+
+Definition make_cmp_imm_eq (c: condition) (args: list reg) (vl: list aval)
+ (n: int) (r1: reg) (v1: aval) :=
+ if Int.eq_dec n Int.one && vincl v1 (Uns Ptop 1) then (Omove, r1 :: nil)
+ else if Int.eq_dec n Int.zero && vincl v1 (Uns Ptop 1) then (Oxorimm Int.one, r1 :: nil)
+ else make_cmp_base c args vl.
+
+Definition make_cmp_imm_ne (c: condition) (args: list reg) (vl: list aval)
+ (n: int) (r1: reg) (v1: aval) :=
+ if Int.eq_dec n Int.zero && vincl v1 (Uns Ptop 1) then (Omove, r1 :: nil)
+ else if Int.eq_dec n Int.one && vincl v1 (Uns Ptop 1) then (Oxorimm Int.one, r1 :: nil)
+ else make_cmp_base c args vl.
+
+Nondetfunction make_cmp (c: condition) (args: list reg) (vl: list aval) :=
+ match c, args, vl with
+ | Ccompimm Ceq n, r1 :: nil, v1 :: nil =>
+ make_cmp_imm_eq c args vl n r1 v1
+ | Ccompimm Cne n, r1 :: nil, v1 :: nil =>
+ make_cmp_imm_ne c args vl n r1 v1
+ | Ccompuimm Ceq n, r1 :: nil, v1 :: nil =>
+ make_cmp_imm_eq c args vl n r1 v1
+ | Ccompuimm Cne n, r1 :: nil, v1 :: nil =>
+ make_cmp_imm_ne c args vl n r1 v1
+ | _, _, _ =>
+ make_cmp_base c args vl
+ end.
+
+Definition make_select (c: condition) (ty: typ)
+ (r1 r2: reg) (args: list reg) (vl: list aval) :=
+ match resolve_branch (eval_static_condition c vl) with
+ | Some b => (Omove, (if b then r1 else r2) :: nil)
+ | None =>
+ let (c', args') := cond_strength_reduction c args vl in
+ (Osel c' ty, r1 :: r2 :: args')
+ end.
+
+Definition make_addimm (n: int) (r: reg) :=
+ if Int.eq n Int.zero
+ then (Omove, r :: nil)
+ else (Oaddimm n, r :: nil).
+
+Definition make_shlimm (n: int) (r1 r2: reg) :=
+ if Int.eq n Int.zero then (Omove, r1 :: nil)
+ else if Int.ltu n Int.iwordsize then (Oshift Slsl (mk_amount32 n), r1 :: nil)
+ else (Oshl, r1 :: r2 :: nil).
+
+Definition make_shrimm (n: int) (r1 r2: reg) :=
+ if Int.eq n Int.zero then (Omove, r1 :: nil)
+ else if Int.ltu n Int.iwordsize then (Oshift Sasr (mk_amount32 n), r1 :: nil)
+ else (Oshr, r1 :: r2 :: nil).
+
+Definition make_shruimm (n: int) (r1 r2: reg) :=
+ if Int.eq n Int.zero then (Omove, r1 :: nil)
+ else if Int.ltu n Int.iwordsize then (Oshift Slsr (mk_amount32 n), r1 :: nil)
+ else (Oshru, r1 :: r2 :: nil).
+
+Definition make_mulimm (n: int) (r1 r2: reg) :=
+ if Int.eq n Int.zero then
+ (Ointconst Int.zero, nil)
+ else if Int.eq n Int.one then
+ (Omove, r1 :: nil)
+ else
+ match Int.is_power2 n with
+ | Some l => (Oshift Slsl (mk_amount32 l), r1 :: nil)
+ | None => (Omul, r1 :: r2 :: nil)
+ end.
+
+Definition make_andimm (n: int) (r: reg) (a: aval) :=
+ if Int.eq n Int.zero then (Ointconst Int.zero, nil)
+ else if Int.eq n Int.mone then (Omove, r :: nil)
+ else if match a with Uns _ m => Int.eq (Int.zero_ext m (Int.not n)) Int.zero
+ | _ => false end
+ then (Omove, r :: nil)
+ else (Oandimm n, r :: nil).
+
+Definition make_orimm (n: int) (r: reg) :=
+ if Int.eq n Int.zero then (Omove, r :: nil)
+ else if Int.eq n Int.mone then (Ointconst Int.mone, nil)
+ else (Oorimm n, r :: nil).
+
+Definition make_xorimm (n: int) (r: reg) :=
+ if Int.eq n Int.zero then (Omove, r :: nil)
+ else (Oxorimm n, r :: nil).
+
+Definition make_divimm n (r1 r2: reg) :=
+ if Int.eq n Int.one then
+ (Omove, r1 :: nil)
+ else
+ match Int.is_power2 n with
+ | Some l => if Int.ltu l (Int.repr 31)
+ then (Oshrximm l, r1 :: nil)
+ else (Odiv, r1 :: r2 :: nil)
+ | None => (Odiv, r1 :: r2 :: nil)
+ end.
+
+Definition make_divuimm n (r1 r2: reg) :=
+ if Int.eq n Int.one then
+ (Omove, r1 :: nil)
+ else
+ match Int.is_power2 n with
+ | Some l => (Oshift Slsr (mk_amount32 l), r1 :: nil)
+ | None => (Odivu, r1 :: r2 :: nil)
+ end.
+
+Definition make_addlimm (n: int64) (r: reg) :=
+ if Int64.eq n Int64.zero
+ then (Omove, r :: nil)
+ else (Oaddlimm n, r :: nil).
+
+Definition make_shllimm (n: int) (r1 r2: reg) :=
+ if Int.eq n Int.zero then (Omove, r1 :: nil)
+ else if Int.ltu n Int64.iwordsize' then (Oshiftl Slsl (mk_amount64 n), r1 :: nil)
+ else (Oshll, r1 :: r2 :: nil).
+
+Definition make_shrlimm (n: int) (r1 r2: reg) :=
+ if Int.eq n Int.zero then (Omove, r1 :: nil)
+ else if Int.ltu n Int64.iwordsize' then (Oshiftl Sasr (mk_amount64 n), r1 :: nil)
+ else (Oshrl, r1 :: r2 :: nil).
+
+Definition make_shrluimm (n: int) (r1 r2: reg) :=
+ if Int.eq n Int.zero then (Omove, r1 :: nil)
+ else if Int.ltu n Int64.iwordsize' then (Oshiftl Slsr (mk_amount64 n), r1 :: nil)
+ else (Oshrlu, r1 :: r2 :: nil).
+
+Definition make_mullimm (n: int64) (r1 r2: reg) :=
+ if Int64.eq n Int64.zero then
+ (Olongconst Int64.zero, nil)
+ else if Int64.eq n Int64.one then
+ (Omove, r1 :: nil)
+ else
+ match Int64.is_power2' n with
+ | Some l => (Oshiftl Slsl (mk_amount64 l), r1 :: nil)
+ | None => (Omull, r1 :: r2 :: nil)
+ end.
+
+Definition make_andlimm (n: int64) (r: reg) (a: aval) :=
+ if Int64.eq n Int64.zero then (Olongconst Int64.zero, nil)
+ else if Int64.eq n Int64.mone then (Omove, r :: nil)
+ else (Oandlimm n, r :: nil).
+
+Definition make_orlimm (n: int64) (r: reg) :=
+ if Int64.eq n Int64.zero then (Omove, r :: nil)
+ else if Int64.eq n Int64.mone then (Olongconst Int64.mone, nil)
+ else (Oorlimm n, r :: nil).
+
+Definition make_xorlimm (n: int64) (r: reg) :=
+ if Int64.eq n Int64.zero then (Omove, r :: nil)
+ else (Oxorlimm n, r :: nil).
+
+Definition make_divlimm n (r1 r2: reg) :=
+ match Int64.is_power2' n with
+ | Some l => if Int.ltu l (Int.repr 63)
+ then (Oshrlximm l, r1 :: nil)
+ else (Odivl, r1 :: r2 :: nil)
+ | None => (Odivl, r1 :: r2 :: nil)
+ end.
+
+Definition make_divluimm n (r1 r2: reg) :=
+ match Int64.is_power2' n with
+ | Some l => (Oshiftl Slsr (mk_amount64 l), r1 :: nil)
+ | None => (Odivlu, r1 :: r2 :: nil)
+ end.
+
+Definition make_mulfimm (n: float) (r r1 r2: reg) :=
+ if Float.eq_dec n (Float.of_int (Int.repr 2))
+ then (Oaddf, r :: r :: nil)
+ else (Omulf, r1 :: r2 :: nil).
+
+Definition make_mulfsimm (n: float32) (r r1 r2: reg) :=
+ if Float32.eq_dec n (Float32.of_int (Int.repr 2))
+ then (Oaddfs, r :: r :: nil)
+ else (Omulfs, r1 :: r2 :: nil).
+
+Definition make_zext (s: Z) (r: reg) (a: aval) :=
+ if vincl a (Uns Ptop s) then (Omove, r :: nil) else (Ozext s, r :: nil).
+
+Definition make_sext (s: Z) (r: reg) (a: aval) :=
+ if vincl a (Sgn Ptop s) then (Omove, r :: nil) else (Osext s, r :: nil).
+
+Nondetfunction op_strength_reduction
+ (op: operation) (args: list reg) (vl: list aval) :=
+ match op, args, vl with
+ | Oadd, r1 :: r2 :: nil, I n1 :: v2 :: nil => make_addimm n1 r2
+ | Oadd, r1 :: r2 :: nil, v1 :: I n2 :: nil => make_addimm n2 r1
+ | Oaddshift s a, r1 :: r2 :: nil, v1 :: I n2 :: nil => make_addimm (eval_static_shift s n2 a) r1
+ | Osub, r1 :: r2 :: nil, v1 :: I n2 :: nil => make_addimm (Int.neg n2) r1
+ | Osubshift s a, r1 :: r2 :: nil, v1 :: I n2 :: nil => make_addimm (Int.neg (eval_static_shift s n2 a)) r1
+ | Omul, r1 :: r2 :: nil, I n1 :: v2 :: nil => make_mulimm n1 r2 r1
+ | Omul, r1 :: r2 :: nil, v1 :: I n2 :: nil => make_mulimm n2 r1 r2
+ | Odiv, r1 :: r2 :: nil, v1 :: I n2 :: nil => make_divimm n2 r1 r2
+ | Odivu, r1 :: r2 :: nil, v1 :: I n2 :: nil => make_divuimm n2 r1 r2
+ | Oand, r1 :: r2 :: nil, I n1 :: v2 :: nil => make_andimm n1 r2 v2
+ | Oand, r1 :: r2 :: nil, v1 :: I n2 :: nil => make_andimm n2 r1 v1
+ | Oandshift s a, r1 :: r2 :: nil, v1 :: I n2 :: nil => make_andimm (eval_static_shift s n2 a) r1 v1
+ | Oandimm n, r1 :: nil, v1 :: nil => make_andimm n r1 v1
+ | Oor, r1 :: r2 :: nil, I n1 :: v2 :: nil => make_orimm n1 r2
+ | Oor, r1 :: r2 :: nil, v1 :: I n2 :: nil => make_orimm n2 r1
+ | Oorshift s a, r1 :: r2 :: nil, v1 :: I n2 :: nil => make_orimm (eval_static_shift s n2 a) r1
+ | Oxor, r1 :: r2 :: nil, I n1 :: v2 :: nil => make_xorimm n1 r2
+ | Oxor, r1 :: r2 :: nil, v1 :: I n2 :: nil => make_xorimm n2 r1
+ | Oxorshift s a, r1 :: r2 :: nil, v1 :: I n2 :: nil => make_xorimm (eval_static_shift s n2 a) r1
+ | Obic, r1 :: r2 :: nil, v1 :: I n2 :: nil => make_andimm (Int.not n2) r1 v1
+ | Obicshift s a, r1 :: r2 :: nil, v1 :: I n2 :: nil => make_andimm (Int.not (eval_static_shift s n2 a)) r1 v1
+ | Oorn, r1 :: r2 :: nil, v1 :: I n2 :: nil => make_orimm (Int.not n2) r1
+ | Oornshift s a, r1 :: r2 :: nil, v1 :: I n2 :: nil => make_orimm (Int.not (eval_static_shift s n2 a)) r1
+ | Oeqv, r1 :: r2 :: nil, v1 :: I n2 :: nil => make_xorimm (Int.not n2) r1
+ | Oeqvshift s a, r1 :: r2 :: nil, v1 :: I n2 :: nil => make_xorimm (Int.not (eval_static_shift s n2 a)) r1
+ | Oshl, r1 :: r2 :: nil, v1 :: I n2 :: nil => make_shlimm n2 r1 r2
+ | Oshr, r1 :: r2 :: nil, v1 :: I n2 :: nil => make_shrimm n2 r1 r2
+ | Oshru, r1 :: r2 :: nil, v1 :: I n2 :: nil => make_shruimm n2 r1 r2
+ | Ozext s, r1 :: nil, v1 :: nil => make_zext s r1 v1
+ | Osext s, r1 :: nil, v1 :: nil => make_sext s r1 v1
+
+ | Oaddl, r1 :: r2 :: nil, L n1 :: v2 :: nil => make_addlimm n1 r2
+ | Oaddl, r1 :: r2 :: nil, v1 :: L n2 :: nil => make_addlimm n2 r1
+ | Oaddlshift s a, r1 :: r2 :: nil, v1 :: L n2 :: nil => make_addlimm (eval_static_shiftl s n2 a) r1
+ | Oaddlext x a, r1 :: r2 :: nil, v1 :: I n2 :: nil => make_addlimm (eval_static_extend x n2 a) r1
+ | Osubl, r1 :: r2 :: nil, v1 :: L n2 :: nil => make_addlimm (Int64.neg n2) r1
+ | Osublshift s a, r1 :: r2 :: nil, v1 :: L n2 :: nil => make_addlimm (Int64.neg (eval_static_shiftl s n2 a)) r1
+ | Osublext x a, r1 :: r2 :: nil, v1 :: I n2 :: nil => make_addlimm (Int64.neg (eval_static_extend x n2 a)) r1
+ | Omull, r1 :: r2 :: nil, L n1 :: v2 :: nil => make_mullimm n1 r2 r1
+ | Omull, r1 :: r2 :: nil, v1 :: L n2 :: nil => make_mullimm n2 r1 r2
+ | Odivl, r1 :: r2 :: nil, v1 :: L n2 :: nil => make_divlimm n2 r1 r2
+ | Odivlu, r1 :: r2 :: nil, v1 :: L n2 :: nil => make_divluimm n2 r1 r2
+ | Oandl, r1 :: r2 :: nil, L n1 :: v2 :: nil => make_andlimm n1 r2 v2
+ | Oandl, r1 :: r2 :: nil, v1 :: L n2 :: nil => make_andlimm n2 r1 v1
+ | Oandlshift s a, r1 :: r2 :: nil, v1 :: L n2 :: nil => make_andlimm (eval_static_shiftl s n2 a) r1 v1
+ | Oandlimm n, r1 :: nil, v1 :: nil => make_andlimm n r1 v1
+ | Oorl, r1 :: r2 :: nil, L n1 :: v2 :: nil => make_orlimm n1 r2
+ | Oorl, r1 :: r2 :: nil, v1 :: L n2 :: nil => make_orlimm n2 r1
+ | Oorlshift s a, r1 :: r2 :: nil, v1 :: L n2 :: nil => make_orlimm (eval_static_shiftl s n2 a) r1
+ | Oxorl, r1 :: r2 :: nil, L n1 :: v2 :: nil => make_xorlimm n1 r2
+ | Oxorl, r1 :: r2 :: nil, v1 :: L n2 :: nil => make_xorlimm n2 r1
+ | Oxorlshift s a, r1 :: r2 :: nil, v1 :: L n2 :: nil => make_xorlimm (eval_static_shiftl s n2 a) r1
+ | Obicl, r1 :: r2 :: nil, v1 :: L n2 :: nil => make_andlimm (Int64.not n2) r1 v1
+ | Obiclshift s a, r1 :: r2 :: nil, v1 :: L n2 :: nil => make_andlimm (Int64.not (eval_static_shiftl s n2 a)) r1 v1
+ | Oornl, r1 :: r2 :: nil, v1 :: L n2 :: nil => make_orlimm (Int64.not n2) r1
+ | Oornlshift s a, r1 :: r2 :: nil, v1 :: L n2 :: nil => make_orlimm (Int64.not (eval_static_shiftl s n2 a)) r1
+ | Oeqvl, r1 :: r2 :: nil, v1 :: L n2 :: nil => make_xorlimm (Int64.not n2) r1
+ | Oeqvlshift s a, r1 :: r2 :: nil, v1 :: L n2 :: nil => make_xorlimm (Int64.not (eval_static_shiftl s n2 a)) r1
+ | Oshll, r1 :: r2 :: nil, v1 :: I n2 :: nil => make_shllimm n2 r1 r2
+ | Oshrl, r1 :: r2 :: nil, v1 :: I n2 :: nil => make_shrlimm n2 r1 r2
+ | Oshrlu, r1 :: r2 :: nil, v1 :: I n2 :: nil => make_shrluimm n2 r1 r2
+ | Ocmp c, args, vl => make_cmp c args vl
+ | Osel c ty, r1 :: r2 :: args, v1 :: v2 :: vl => make_select c ty r1 r2 args vl
+ | Omulf, r1 :: r2 :: nil, v1 :: F n2 :: nil => make_mulfimm n2 r1 r1 r2
+ | Omulf, r1 :: r2 :: nil, F n1 :: v2 :: nil => make_mulfimm n1 r2 r1 r2
+ | Omulfs, r1 :: r2 :: nil, v1 :: FS n2 :: nil => make_mulfsimm n2 r1 r1 r2
+ | Omulfs, r1 :: r2 :: nil, FS n1 :: v2 :: nil => make_mulfsimm n1 r2 r1 r2
+ | _, _, _ => (op, args)
+ end.
+
+Nondetfunction addr_strength_reduction
+ (addr: addressing) (args: list reg) (vl: list aval) :=
+ match addr, args, vl with
+ | Aindexed n, r1 :: nil, Ptr(Gl symb n1) :: nil =>
+ (Aglobal symb (Ptrofs.add n1 (Ptrofs.of_int64 n)), nil)
+ | Aindexed n, r1 :: nil, Ptr(Stk n1) :: nil =>
+ (Ainstack (Ptrofs.add n1 (Ptrofs.of_int64 n)), nil)
+ | Aindexed2, r1 :: r2 :: nil, Ptr(Stk n1) :: L n2 :: nil =>
+ (Ainstack (Ptrofs.add n1 (Ptrofs.of_int64 n2)), nil)
+ | Aindexed2, r1 :: r2 :: nil, L n1 :: Ptr(Stk n2) :: nil =>
+ (Ainstack (Ptrofs.add (Ptrofs.of_int64 n1) n2), nil)
+ | Aindexed2, r1 :: r2 :: nil, L n1 :: v2 :: nil =>
+ (Aindexed n1, r2 :: nil)
+ | Aindexed2, r1 :: r2 :: nil, v1 :: L n2 :: nil =>
+ (Aindexed n2, r1 :: nil)
+ | Aindexed2shift a, r1 :: r2 :: nil, Ptr(Stk n1) :: L n2 :: nil =>
+ (Ainstack (Ptrofs.add n1 (Ptrofs.of_int64 (Int64.shl' n2 a))), nil)
+ | Aindexed2shift a, r1 :: r2 :: nil, v1 :: L n2 :: nil =>
+ (Aindexed (Int64.shl' n2 a), r1 :: nil)
+ | Aindexed2ext x a, r1 :: r2 :: nil, Ptr(Stk n1) :: I n2 :: nil =>
+ (Ainstack (Ptrofs.add n1 (Ptrofs.of_int64 (eval_static_extend x n2 a))), nil)
+ | Aindexed2ext x a, r1 :: r2 :: nil, v1 :: I n2 :: nil =>
+ (Aindexed (eval_static_extend x n2 a), r1 :: nil)
+ | _, _, _ =>
+ (addr, args)
+ end.
+
diff --git a/aarch64/ConstpropOpproof.v b/aarch64/ConstpropOpproof.v
new file mode 100644
index 00000000..deab7cd4
--- /dev/null
+++ b/aarch64/ConstpropOpproof.v
@@ -0,0 +1,838 @@
+(* *********************************************************************)
+(* *)
+(* 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 operator strength reduction. *)
+
+Require Import Coqlib Compopts.
+Require Import Integers Floats Values Memory Globalenvs Events.
+Require Import Op Registers RTL ValueDomain ValueAOp ValueAnalysis.
+Require Import ConstpropOp.
+
+Local Transparent Archi.ptr64.
+
+Section STRENGTH_REDUCTION.
+
+Variable bc: block_classification.
+Variable ge: genv.
+Hypothesis GENV: genv_match bc ge.
+Variable sp: block.
+Hypothesis STACK: bc sp = BCstack.
+Variable ae: AE.t.
+Variable e: regset.
+Variable m: mem.
+Hypothesis MATCH: ematch bc e ae.
+
+Lemma match_G:
+ forall r id ofs,
+ AE.get r ae = Ptr(Gl id ofs) -> Val.lessdef e#r (Genv.symbol_address ge id ofs).
+Proof.
+ intros. apply vmatch_ptr_gl with bc; auto. rewrite <- H. apply MATCH.
+Qed.
+
+Lemma match_S:
+ forall r ofs,
+ AE.get r ae = Ptr(Stk ofs) -> Val.lessdef e#r (Vptr sp ofs).
+Proof.
+ intros. apply vmatch_ptr_stk with bc; auto. rewrite <- H. apply MATCH.
+Qed.
+
+Ltac InvApproxRegs :=
+ match goal with
+ | [ H: _ :: _ = _ :: _ |- _ ] =>
+ injection H; clear H; intros; InvApproxRegs
+ | [ H: ?v = AE.get ?r ae |- _ ] =>
+ generalize (MATCH r); rewrite <- H; clear H; intro; InvApproxRegs
+ | _ => idtac
+ end.
+
+Ltac SimplVM :=
+ match goal with
+ | [ H: vmatch _ ?v (I ?n) |- _ ] =>
+ let E := fresh in
+ assert (E: v = Vint n) by (inversion H; auto);
+ rewrite E in *; clear H; SimplVM
+ | [ H: vmatch _ ?v (L ?n) |- _ ] =>
+ let E := fresh in
+ assert (E: v = Vlong n) by (inversion H; auto);
+ rewrite E in *; clear H; SimplVM
+ | [ H: vmatch _ ?v (F ?n) |- _ ] =>
+ let E := fresh in
+ assert (E: v = Vfloat n) by (inversion H; auto);
+ rewrite E in *; clear H; SimplVM
+ | [ H: vmatch _ ?v (FS ?n) |- _ ] =>
+ let E := fresh in
+ assert (E: v = Vsingle n) by (inversion H; auto);
+ rewrite E in *; clear H; SimplVM
+ | [ H: vmatch _ ?v (Ptr(Gl ?id ?ofs)) |- _ ] =>
+ let E := fresh in
+ assert (E: Val.lessdef v (Genv.symbol_address ge id ofs)) by (eapply vmatch_ptr_gl; eauto);
+ clear H; SimplVM
+ | [ H: vmatch _ ?v (Ptr(Stk ?ofs)) |- _ ] =>
+ let E := fresh in
+ assert (E: Val.lessdef v (Vptr sp ofs)) by (eapply vmatch_ptr_stk; eauto);
+ clear H; SimplVM
+ | _ => idtac
+ end.
+
+Lemma const_for_result_correct:
+ forall a op v,
+ const_for_result a = Some op ->
+ vmatch bc v a ->
+ exists v', eval_operation ge (Vptr sp Ptrofs.zero) op nil m = Some v' /\ Val.lessdef v v'.
+Proof.
+ unfold const_for_result; intros; destruct a; inv H; SimplVM.
+- (* integer *)
+ exists (Vint n); auto.
+- (* long *)
+ exists (Vlong n); auto.
+- (* float *)
+ destruct (Compopts.generate_float_constants tt); inv H2. exists (Vfloat f); auto.
+- (* single *)
+ destruct (Compopts.generate_float_constants tt); inv H2. exists (Vsingle f); auto.
+- (* pointer *)
+ destruct p; try discriminate; SimplVM.
+ + (* global *)
+ inv H2. exists (Genv.symbol_address ge id ofs); auto.
+ + (* stack *)
+ inv H2. exists (Vptr sp ofs); split; auto. simpl. rewrite Ptrofs.add_zero_l; auto.
+Qed.
+
+Lemma eval_static_shift_correct: forall s v a,
+ eval_shift s (Vint v) a = Vint (eval_static_shift s v a).
+Proof.
+ intros; destruct s; simpl; rewrite ? a32_range; auto.
+Qed.
+
+Lemma eval_static_shiftl_correct: forall s v a,
+ eval_shiftl s (Vlong v) a = Vlong (eval_static_shiftl s v a).
+Proof.
+ intros; destruct s; simpl; rewrite ? a64_range; auto.
+Qed.
+
+Lemma eval_static_extend_correct: forall x v a,
+ eval_extend x (Vint v) a = Vlong (eval_static_extend x v a).
+Proof.
+ unfold eval_extend, eval_static_extend; intros; destruct x; simpl; rewrite ? a64_range; auto.
+Qed.
+
+Lemma cond_strength_reduction_correct:
+ forall cond args vl,
+ vl = map (fun r => AE.get r ae) args ->
+ let (cond', args') := cond_strength_reduction cond args vl in
+ eval_condition cond' e##args' m = eval_condition cond e##args m.
+Proof.
+ intros until vl. unfold cond_strength_reduction.
+ case (cond_strength_reduction_match cond args vl); simpl; intros; InvApproxRegs; SimplVM.
+- apply Val.swap_cmp_bool.
+- auto.
+- apply Val.swap_cmpu_bool.
+- auto.
+- rewrite eval_static_shift_correct; auto.
+- rewrite eval_static_shift_correct; auto.
+- apply Val.swap_cmpl_bool.
+- auto.
+- apply Val.swap_cmplu_bool.
+- auto.
+- rewrite eval_static_shiftl_correct; auto.
+- rewrite eval_static_shiftl_correct; auto.
+- destruct (Float.eq_dec n1 Float.zero).
+ subst n1. simpl. destruct (e#r2); simpl; auto. rewrite Float.cmp_swap. auto.
+ simpl. rewrite H1; auto.
+- destruct (Float.eq_dec n2 Float.zero).
+ subst n2. simpl. auto.
+ simpl. rewrite H1; auto.
+- destruct (Float.eq_dec n1 Float.zero).
+ subst n1. simpl. destruct (e#r2); simpl; auto. rewrite Float.cmp_swap. auto.
+ simpl. rewrite H1; auto.
+- destruct (Float.eq_dec n2 Float.zero); simpl; auto.
+ subst n2; auto.
+ rewrite H1; auto.
+- destruct (Float32.eq_dec n1 Float32.zero).
+ subst n1. simpl. destruct (e#r2); simpl; auto. rewrite Float32.cmp_swap. auto.
+ simpl. rewrite H1; auto.
+- destruct (Float32.eq_dec n2 Float32.zero).
+ subst n2. simpl. auto.
+ simpl. rewrite H1; auto.
+- destruct (Float32.eq_dec n1 Float32.zero).
+ subst n1. simpl. destruct (e#r2); simpl; auto. rewrite Float32.cmp_swap. auto.
+ simpl. rewrite H1; auto.
+- destruct (Float32.eq_dec n2 Float32.zero); simpl; auto.
+ subst n2; auto.
+ rewrite H1; auto.
+- auto.
+Qed.
+
+Lemma make_cmp_base_correct:
+ forall c args vl,
+ vl = map (fun r => AE.get r ae) args ->
+ let (op', args') := make_cmp_base c args vl in
+ exists v, eval_operation ge (Vptr sp Ptrofs.zero) op' e##args' m = Some v
+ /\ Val.lessdef (Val.of_optbool (eval_condition c e##args m)) v.
+Proof.
+ intros. unfold make_cmp_base.
+ generalize (cond_strength_reduction_correct c args vl H).
+ destruct (cond_strength_reduction c args vl) as [c' args']. intros EQ.
+ econstructor; split. simpl; eauto. rewrite EQ. auto.
+Qed.
+
+Lemma make_cmp_correct:
+ forall c args vl,
+ vl = map (fun r => AE.get r ae) args ->
+ let (op', args') := make_cmp c args vl in
+ exists v, eval_operation ge (Vptr sp Ptrofs.zero) op' e##args' m = Some v
+ /\ Val.lessdef (Val.of_optbool (eval_condition c e##args m)) v.
+Proof.
+ intros c args vl.
+ assert (Y: forall r, vincl (AE.get r ae) (Uns Ptop 1) = true ->
+ e#r = Vundef \/ e#r = Vint Int.zero \/ e#r = Vint Int.one).
+ { intros. apply vmatch_Uns_1 with bc Ptop. eapply vmatch_ge. eapply vincl_ge; eauto. apply MATCH. }
+ unfold make_cmp. case (make_cmp_match c args vl); intros.
+- unfold make_cmp_imm_eq.
+ destruct (Int.eq_dec n Int.one && vincl v1 (Uns Ptop 1)) eqn:E1.
++ simpl in H; inv H. InvBooleans. subst n.
+ exists (e#r1); split; auto. simpl.
+ exploit Y; eauto. intros [A | [A | A]]; rewrite A; simpl; auto.
++ destruct (Int.eq_dec n Int.zero && vincl v1 (Uns Ptop 1)) eqn:E0.
+* simpl in H; inv H. InvBooleans. subst n.
+ exists (Val.xor e#r1 (Vint Int.one)); split; auto. simpl.
+ exploit Y; eauto. intros [A | [A | A]]; rewrite A; simpl; auto.
+* apply make_cmp_base_correct; auto.
+- unfold make_cmp_imm_ne.
+ destruct (Int.eq_dec n Int.zero && vincl v1 (Uns Ptop 1)) eqn:E0.
++ simpl in H; inv H. InvBooleans. subst n.
+ exists (e#r1); split; auto. simpl.
+ exploit Y; eauto. intros [A | [A | A]]; rewrite A; simpl; auto.
++ destruct (Int.eq_dec n Int.one && vincl v1 (Uns Ptop 1)) eqn:E1.
+* simpl in H; inv H. InvBooleans. subst n.
+ exists (Val.xor e#r1 (Vint Int.one)); split; auto. simpl.
+ exploit Y; eauto. intros [A | [A | A]]; rewrite A; simpl; auto.
+* apply make_cmp_base_correct; auto.
+- unfold make_cmp_imm_eq.
+ destruct (Int.eq_dec n Int.one && vincl v1 (Uns Ptop 1)) eqn:E1.
++ simpl in H; inv H. InvBooleans. subst n.
+ exists (e#r1); split; auto. simpl.
+ exploit Y; eauto. intros [A | [A | A]]; rewrite A; simpl; auto.
++ destruct (Int.eq_dec n Int.zero && vincl v1 (Uns Ptop 1)) eqn:E0.
+* simpl in H; inv H. InvBooleans. subst n.
+ exists (Val.xor e#r1 (Vint Int.one)); split; auto. simpl.
+ exploit Y; eauto. intros [A | [A | A]]; rewrite A; simpl; auto.
+* apply make_cmp_base_correct; auto.
+- unfold make_cmp_imm_ne.
+ destruct (Int.eq_dec n Int.zero && vincl v1 (Uns Ptop 1)) eqn:E0.
++ simpl in H; inv H. InvBooleans. subst n.
+ exists (e#r1); split; auto. simpl.
+ exploit Y; eauto. intros [A | [A | A]]; rewrite A; simpl; auto.
++ destruct (Int.eq_dec n Int.one && vincl v1 (Uns Ptop 1)) eqn:E1.
+* simpl in H; inv H. InvBooleans. subst n.
+ exists (Val.xor e#r1 (Vint Int.one)); split; auto. simpl.
+ exploit Y; eauto. intros [A | [A | A]]; rewrite A; simpl; auto.
+* apply make_cmp_base_correct; auto.
+- apply make_cmp_base_correct; auto.
+Qed.
+
+Lemma make_select_correct:
+ forall c ty r1 r2 args vl,
+ vl = map (fun r => AE.get r ae) args ->
+ let (op', args') := make_select c ty r1 r2 args vl in
+ exists v, eval_operation ge (Vptr sp Ptrofs.zero) op' e##args' m = Some v
+ /\ Val.lessdef (Val.select (eval_condition c e##args m) e#r1 e#r2 ty) v.
+Proof.
+ unfold make_select; intros.
+ destruct (resolve_branch (eval_static_condition c vl)) as [b|] eqn:RB.
+- exists (if b then e#r1 else e#r2); split.
++ simpl. destruct b; auto.
++ destruct (eval_condition c e##args m) as [b'|] eqn:EC; simpl; auto.
+ assert (b = b').
+ { eapply resolve_branch_sound; eauto.
+ rewrite <- EC. apply eval_static_condition_sound with bc.
+ subst vl. exact (aregs_sound _ _ _ args MATCH). }
+ subst b'. apply Val.lessdef_normalize.
+- generalize (cond_strength_reduction_correct c args vl H).
+ destruct (cond_strength_reduction c args vl) as [cond' args']; intros EQ.
+ econstructor; split. simpl; eauto. rewrite EQ; auto.
+Qed.
+
+Lemma make_addimm_correct:
+ forall n r,
+ let (op, args) := make_addimm n r in
+ exists v, eval_operation ge (Vptr sp Ptrofs.zero) op e##args m = Some v /\ Val.lessdef (Val.add e#r (Vint n)) v.
+Proof.
+ intros. unfold make_addimm.
+ predSpec Int.eq Int.eq_spec n Int.zero; intros.
+ subst. exists (e#r); split; auto.
+ destruct (e#r); simpl; rewrite ?Int.add_zero; auto.
+ exists (Val.add e#r (Vint n)); split; auto.
+Qed.
+
+Lemma make_shlimm_correct:
+ forall n r1 r2,
+ e#r2 = Vint n ->
+ let (op, args) := make_shlimm n r1 r2 in
+ exists v, eval_operation ge (Vptr sp Ptrofs.zero) op e##args m = Some v /\ Val.lessdef (Val.shl e#r1 (Vint n)) v.
+Proof.
+Local Opaque mk_amount32.
+ intros; unfold make_shlimm.
+ predSpec Int.eq Int.eq_spec n Int.zero; intros. subst.
+ exists (e#r1); split; auto. destruct (e#r1); simpl; auto. rewrite Int.shl_zero. auto.
+ destruct (Int.ltu n Int.iwordsize) eqn:L.
+ econstructor; split. simpl. eauto. rewrite mk_amount32_eq; auto.
+ econstructor; split. simpl. eauto. rewrite H; auto.
+Qed.
+
+Lemma make_shrimm_correct:
+ forall n r1 r2,
+ e#r2 = Vint n ->
+ let (op, args) := make_shrimm n r1 r2 in
+ exists v, eval_operation ge (Vptr sp Ptrofs.zero) op e##args m = Some v /\ Val.lessdef (Val.shr e#r1 (Vint n)) v.
+Proof.
+ intros; unfold make_shrimm.
+ predSpec Int.eq Int.eq_spec n Int.zero; intros. subst.
+ exists (e#r1); split; auto. destruct (e#r1); simpl; auto. rewrite Int.shr_zero. auto.
+ destruct (Int.ltu n Int.iwordsize) eqn:L.
+ econstructor; split. simpl. eauto. rewrite mk_amount32_eq; auto.
+ econstructor; split. simpl. eauto. rewrite H; auto.
+Qed.
+
+Lemma make_shruimm_correct:
+ forall n r1 r2,
+ e#r2 = Vint n ->
+ let (op, args) := make_shruimm n r1 r2 in
+ exists v, eval_operation ge (Vptr sp Ptrofs.zero) op e##args m = Some v /\ Val.lessdef (Val.shru e#r1 (Vint n)) v.
+Proof.
+ intros; unfold make_shruimm.
+ predSpec Int.eq Int.eq_spec n Int.zero; intros. subst.
+ exists (e#r1); split; auto. destruct (e#r1); simpl; auto. rewrite Int.shru_zero. auto.
+ destruct (Int.ltu n Int.iwordsize) eqn:L.
+ econstructor; split. simpl. eauto. rewrite mk_amount32_eq; auto.
+ econstructor; split. simpl. eauto. rewrite H; auto.
+Qed.
+
+Lemma make_mulimm_correct:
+ forall n r1 r2,
+ e#r2 = Vint n ->
+ let (op, args) := make_mulimm n r1 r2 in
+ exists v, eval_operation ge (Vptr sp Ptrofs.zero) op e##args m = Some v /\ Val.lessdef (Val.mul e#r1 (Vint n)) v.
+Proof.
+ intros; unfold make_mulimm.
+ predSpec Int.eq Int.eq_spec n Int.zero; intros. subst.
+ exists (Vint Int.zero); split; auto. destruct (e#r1); simpl; auto. rewrite Int.mul_zero; auto.
+ predSpec Int.eq Int.eq_spec n Int.one; intros. subst.
+ exists (e#r1); split; auto. destruct (e#r1); simpl; auto. rewrite Int.mul_one; auto.
+ destruct (Int.is_power2 n) eqn:?; intros.
+ rewrite (Val.mul_pow2 e#r1 _ _ Heqo). econstructor; split. simpl; eauto.
+ rewrite mk_amount32_eq; auto. eapply Int.is_power2_range; eauto.
+ econstructor; split; eauto. simpl. rewrite H; auto.
+Qed.
+
+Lemma make_divimm_correct:
+ forall n r1 r2 v,
+ Val.divs e#r1 e#r2 = Some v ->
+ e#r2 = Vint n ->
+ let (op, args) := make_divimm n r1 r2 in
+ exists w, eval_operation ge (Vptr sp Ptrofs.zero) op e##args m = Some w /\ Val.lessdef v w.
+Proof.
+ intros; unfold make_divimm.
+ predSpec Int.eq Int.eq_spec n Int.one; intros. subst. rewrite H0 in H.
+ destruct (e#r1) eqn:?;
+ try (rewrite Val.divs_one in H; exists (Vint i); split; simpl; try rewrite Heqv0; auto);
+ inv H; auto.
+ destruct (Int.is_power2 n) eqn:?.
+ destruct (Int.ltu i (Int.repr 31)) eqn:?.
+ exists v; split; auto. simpl. eapply Val.divs_pow2; eauto. congruence.
+ exists v; auto.
+ exists v; auto.
+Qed.
+
+Lemma make_divuimm_correct:
+ forall n r1 r2 v,
+ Val.divu e#r1 e#r2 = Some v ->
+ e#r2 = Vint n ->
+ let (op, args) := make_divuimm n r1 r2 in
+ exists w, eval_operation ge (Vptr sp Ptrofs.zero) op e##args m = Some w /\ Val.lessdef v w.
+Proof.
+ intros; unfold make_divuimm.
+ predSpec Int.eq Int.eq_spec n Int.one; intros. subst. rewrite H0 in H.
+ destruct (e#r1) eqn:?;
+ try (rewrite Val.divu_one in H; exists (Vint i); split; simpl; try rewrite Heqv0; auto);
+ inv H; auto.
+ destruct (Int.is_power2 n) eqn:?.
+ econstructor; split. simpl; eauto.
+ rewrite mk_amount32_eq by (eapply Int.is_power2_range; eauto).
+ rewrite H0 in H. erewrite Val.divu_pow2 by eauto. auto.
+ exists v; auto.
+Qed.
+
+Lemma make_andimm_correct:
+ forall n r x,
+ vmatch bc e#r x ->
+ let (op, args) := make_andimm n r x in
+ exists v, eval_operation ge (Vptr sp Ptrofs.zero) op e##args m = Some v /\ Val.lessdef (Val.and e#r (Vint n)) v.
+Proof.
+ intros; unfold make_andimm.
+ predSpec Int.eq Int.eq_spec n Int.zero; intros.
+ subst n. exists (Vint Int.zero); split; auto. destruct (e#r); simpl; auto. rewrite Int.and_zero; auto.
+ predSpec Int.eq Int.eq_spec n Int.mone; intros.
+ subst n. exists (e#r); split; auto. destruct (e#r); simpl; auto. rewrite Int.and_mone; auto.
+ destruct (match x with Uns _ k => Int.eq (Int.zero_ext k (Int.not n)) Int.zero
+ | _ => false end) eqn:UNS.
+ destruct x; try congruence.
+ exists (e#r); split; auto.
+ inv H; auto. simpl. replace (Int.and i n) with i; auto.
+ generalize (Int.eq_spec (Int.zero_ext n0 (Int.not n)) Int.zero); rewrite UNS; intro EQ.
+ Int.bit_solve. destruct (zlt i0 n0).
+ replace (Int.testbit n i0) with (negb (Int.testbit Int.zero i0)).
+ rewrite Int.bits_zero. simpl. rewrite andb_true_r. auto.
+ rewrite <- EQ. rewrite Int.bits_zero_ext by omega. rewrite zlt_true by auto.
+ rewrite Int.bits_not by auto. apply negb_involutive.
+ rewrite H6 by auto. auto.
+ econstructor; split; eauto. auto.
+Qed.
+
+Lemma make_orimm_correct:
+ forall n r,
+ let (op, args) := make_orimm n r in
+ exists v, eval_operation ge (Vptr sp Ptrofs.zero) op e##args m = Some v /\ Val.lessdef (Val.or e#r (Vint n)) v.
+Proof.
+ intros; unfold make_orimm.
+ predSpec Int.eq Int.eq_spec n Int.zero; intros.
+ subst n. exists (e#r); split; auto. destruct (e#r); simpl; auto. rewrite Int.or_zero; auto.
+ predSpec Int.eq Int.eq_spec n Int.mone; intros.
+ subst n. exists (Vint Int.mone); split; auto. destruct (e#r); simpl; auto. rewrite Int.or_mone; auto.
+ econstructor; split; eauto. auto.
+Qed.
+
+Lemma make_xorimm_correct:
+ forall n r,
+ let (op, args) := make_xorimm n r in
+ exists v, eval_operation ge (Vptr sp Ptrofs.zero) op e##args m = Some v /\ Val.lessdef (Val.xor e#r (Vint n)) v.
+Proof.
+ intros; unfold make_xorimm.
+ predSpec Int.eq Int.eq_spec n Int.zero; intros.
+ subst n. exists (e#r); split; auto. destruct (e#r); simpl; auto. rewrite Int.xor_zero; auto.
+ predSpec Int.eq Int.eq_spec n Int.mone; intros.
+ subst n. exists (Val.notint e#r); split; auto.
+ econstructor; split; eauto. auto.
+Qed.
+
+Lemma make_addlimm_correct:
+ forall n r,
+ let (op, args) := make_addlimm n r in
+ exists v, eval_operation ge (Vptr sp Ptrofs.zero) op e##args m = Some v /\ Val.lessdef (Val.addl e#r (Vlong n)) v.
+Proof.
+ intros. unfold make_addlimm.
+ predSpec Int64.eq Int64.eq_spec n Int64.zero; intros.
+ subst. exists (e#r); split; auto.
+ destruct (e#r); simpl; auto; rewrite ? Int64.add_zero, ? Ptrofs.add_zero; auto.
+ exists (Val.addl e#r (Vlong n)); split; auto.
+Qed.
+
+Lemma make_shllimm_correct:
+ forall n r1 r2,
+ e#r2 = Vint n ->
+ let (op, args) := make_shllimm n r1 r2 in
+ exists v, eval_operation ge (Vptr sp Ptrofs.zero) op e##args m = Some v /\ Val.lessdef (Val.shll e#r1 (Vint n)) v.
+Proof.
+Local Opaque mk_amount64.
+ intros; unfold make_shllimm.
+ predSpec Int.eq Int.eq_spec n Int.zero; intros. subst.
+ exists (e#r1); split; auto. destruct (e#r1); simpl; auto.
+ unfold Int64.shl'. rewrite Z.shiftl_0_r, Int64.repr_unsigned. auto.
+ destruct (Int.ltu n Int64.iwordsize') eqn:L.
+ econstructor; split. simpl. eauto. rewrite mk_amount64_eq; auto.
+ econstructor; split. simpl. eauto. rewrite H; auto.
+Qed.
+
+Lemma make_shrlimm_correct:
+ forall n r1 r2,
+ e#r2 = Vint n ->
+ let (op, args) := make_shrlimm n r1 r2 in
+ exists v, eval_operation ge (Vptr sp Ptrofs.zero) op e##args m = Some v /\ Val.lessdef (Val.shrl e#r1 (Vint n)) v.
+Proof.
+ intros; unfold make_shrlimm.
+ predSpec Int.eq Int.eq_spec n Int.zero; intros. subst.
+ exists (e#r1); split; auto. destruct (e#r1); simpl; auto.
+ unfold Int64.shr'. rewrite Z.shiftr_0_r, Int64.repr_signed. auto.
+ destruct (Int.ltu n Int64.iwordsize') eqn:L.
+ econstructor; split. simpl. eauto. rewrite mk_amount64_eq; auto.
+ econstructor; split. simpl. eauto. rewrite H; auto.
+Qed.
+
+Lemma make_shrluimm_correct:
+ forall n r1 r2,
+ e#r2 = Vint n ->
+ let (op, args) := make_shrluimm n r1 r2 in
+ exists v, eval_operation ge (Vptr sp Ptrofs.zero) op e##args m = Some v /\ Val.lessdef (Val.shrlu e#r1 (Vint n)) v.
+Proof.
+ intros; unfold make_shrluimm.
+ predSpec Int.eq Int.eq_spec n Int.zero; intros. subst.
+ exists (e#r1); split; auto. destruct (e#r1); simpl; auto.
+ unfold Int64.shru'. rewrite Z.shiftr_0_r, Int64.repr_unsigned. auto.
+ destruct (Int.ltu n Int64.iwordsize') eqn:L.
+ econstructor; split. simpl. eauto. rewrite mk_amount64_eq; auto.
+ econstructor; split. simpl. eauto. rewrite H; auto.
+Qed.
+
+Lemma make_mullimm_correct:
+ forall n r1 r2,
+ e#r2 = Vlong n ->
+ let (op, args) := make_mullimm n r1 r2 in
+ exists v, eval_operation ge (Vptr sp Ptrofs.zero) op e##args m = Some v /\ Val.lessdef (Val.mull e#r1 (Vlong n)) v.
+Proof.
+ intros; unfold make_mullimm.
+ predSpec Int64.eq Int64.eq_spec n Int64.zero; intros. subst.
+ exists (Vlong Int64.zero); split; auto. destruct (e#r1); simpl; auto. rewrite Int64.mul_zero; auto.
+ predSpec Int64.eq Int64.eq_spec n Int64.one; intros. subst.
+ exists (e#r1); split; auto. destruct (e#r1); simpl; auto. rewrite Int64.mul_one; auto.
+ destruct (Int64.is_power2' n) eqn:?; intros.
+ econstructor; split. simpl; eauto.
+ rewrite mk_amount64_eq by (eapply Int64.is_power2'_range; eauto).
+ destruct (e#r1); simpl; auto.
+ erewrite Int64.is_power2'_range by eauto.
+ erewrite Int64.mul_pow2' by eauto. auto.
+ econstructor; split; eauto. simpl; rewrite H; auto.
+Qed.
+
+Lemma make_divlimm_correct:
+ forall n r1 r2 v,
+ Val.divls e#r1 e#r2 = Some v ->
+ e#r2 = Vlong n ->
+ let (op, args) := make_divlimm n r1 r2 in
+ exists w, eval_operation ge (Vptr sp Ptrofs.zero) op e##args m = Some w /\ Val.lessdef v w.
+Proof.
+ intros; unfold make_divlimm.
+ destruct (Int64.is_power2' n) eqn:?. destruct (Int.ltu i (Int.repr 63)) eqn:?.
+ rewrite H0 in H. econstructor; split. simpl; eauto. eapply Val.divls_pow2; eauto. auto.
+ exists v; auto.
+ exists v; auto.
+Qed.
+
+Lemma make_divluimm_correct:
+ forall n r1 r2 v,
+ Val.divlu e#r1 e#r2 = Some v ->
+ e#r2 = Vlong n ->
+ let (op, args) := make_divluimm n r1 r2 in
+ exists w, eval_operation ge (Vptr sp Ptrofs.zero) op e##args m = Some w /\ Val.lessdef v w.
+Proof.
+ intros; unfold make_divluimm.
+ destruct (Int64.is_power2' n) eqn:?.
+ econstructor; split. simpl; eauto.
+ rewrite mk_amount64_eq by (eapply Int64.is_power2'_range; eauto).
+ rewrite H0 in H. destruct (e#r1); inv H. destruct (Int64.eq n Int64.zero); inv H2.
+ simpl.
+ erewrite Int64.is_power2'_range by eauto.
+ erewrite Int64.divu_pow2' by eauto. auto.
+ exists v; auto.
+Qed.
+
+Lemma make_andlimm_correct:
+ forall n r x,
+ let (op, args) := make_andlimm n r x in
+ exists v, eval_operation ge (Vptr sp Ptrofs.zero) op e##args m = Some v /\ Val.lessdef (Val.andl e#r (Vlong n)) v.
+Proof.
+ intros; unfold make_andlimm.
+ predSpec Int64.eq Int64.eq_spec n Int64.zero; intros.
+ subst n. exists (Vlong Int64.zero); split; auto. destruct (e#r); simpl; auto. rewrite Int64.and_zero; auto.
+ predSpec Int64.eq Int64.eq_spec n Int64.mone; intros.
+ subst n. exists (e#r); split; auto. destruct (e#r); simpl; auto. rewrite Int64.and_mone; auto.
+ econstructor; split; eauto. auto.
+Qed.
+
+Lemma make_orlimm_correct:
+ forall n r,
+ let (op, args) := make_orlimm n r in
+ exists v, eval_operation ge (Vptr sp Ptrofs.zero) op e##args m = Some v /\ Val.lessdef (Val.orl e#r (Vlong n)) v.
+Proof.
+ intros; unfold make_orlimm.
+ predSpec Int64.eq Int64.eq_spec n Int64.zero; intros.
+ subst n. exists (e#r); split; auto. destruct (e#r); simpl; auto. rewrite Int64.or_zero; auto.
+ predSpec Int64.eq Int64.eq_spec n Int64.mone; intros.
+ subst n. exists (Vlong Int64.mone); split; auto. destruct (e#r); simpl; auto. rewrite Int64.or_mone; auto.
+ econstructor; split; eauto. auto.
+Qed.
+
+Lemma make_xorlimm_correct:
+ forall n r,
+ let (op, args) := make_xorlimm n r in
+ exists v, eval_operation ge (Vptr sp Ptrofs.zero) op e##args m = Some v /\ Val.lessdef (Val.xorl e#r (Vlong n)) v.
+Proof.
+ intros; unfold make_xorlimm.
+ predSpec Int64.eq Int64.eq_spec n Int64.zero; intros.
+ subst n. exists (e#r); split; auto. destruct (e#r); simpl; auto. rewrite Int64.xor_zero; auto.
+ predSpec Int64.eq Int64.eq_spec n Int64.mone; intros.
+ subst n. exists (Val.notl e#r); split; auto.
+ econstructor; split; eauto. auto.
+Qed.
+
+Lemma make_mulfimm_correct:
+ forall n r1 r2,
+ e#r2 = Vfloat n ->
+ let (op, args) := make_mulfimm n r1 r1 r2 in
+ exists v, eval_operation ge (Vptr sp Ptrofs.zero) op e##args m = Some v /\ Val.lessdef (Val.mulf e#r1 e#r2) v.
+Proof.
+ intros; unfold make_mulfimm.
+ destruct (Float.eq_dec n (Float.of_int (Int.repr 2))); intros.
+ simpl. econstructor; split. eauto. rewrite H; subst n.
+ destruct (e#r1); simpl; auto. rewrite Float.mul2_add; auto.
+ simpl. econstructor; split; eauto.
+Qed.
+
+Lemma make_mulfimm_correct_2:
+ forall n r1 r2,
+ e#r1 = Vfloat n ->
+ let (op, args) := make_mulfimm n r2 r1 r2 in
+ exists v, eval_operation ge (Vptr sp Ptrofs.zero) op e##args m = Some v /\ Val.lessdef (Val.mulf e#r1 e#r2) v.
+Proof.
+ intros; unfold make_mulfimm.
+ destruct (Float.eq_dec n (Float.of_int (Int.repr 2))); intros.
+ simpl. econstructor; split. eauto. rewrite H; subst n.
+ destruct (e#r2); simpl; auto. rewrite Float.mul2_add; auto.
+ rewrite Float.mul_commut; auto.
+ simpl. econstructor; split; eauto.
+Qed.
+
+Lemma make_mulfsimm_correct:
+ forall n r1 r2,
+ e#r2 = Vsingle n ->
+ let (op, args) := make_mulfsimm n r1 r1 r2 in
+ exists v, eval_operation ge (Vptr sp Ptrofs.zero) op e##args m = Some v /\ Val.lessdef (Val.mulfs e#r1 e#r2) v.
+Proof.
+ intros; unfold make_mulfsimm.
+ destruct (Float32.eq_dec n (Float32.of_int (Int.repr 2))); intros.
+ simpl. econstructor; split. eauto. rewrite H; subst n.
+ destruct (e#r1); simpl; auto. rewrite Float32.mul2_add; auto.
+ simpl. econstructor; split; eauto.
+Qed.
+
+Lemma make_mulfsimm_correct_2:
+ forall n r1 r2,
+ e#r1 = Vsingle n ->
+ let (op, args) := make_mulfsimm n r2 r1 r2 in
+ exists v, eval_operation ge (Vptr sp Ptrofs.zero) op e##args m = Some v /\ Val.lessdef (Val.mulfs e#r1 e#r2) v.
+Proof.
+ intros; unfold make_mulfsimm.
+ destruct (Float32.eq_dec n (Float32.of_int (Int.repr 2))); intros.
+ simpl. econstructor; split. eauto. rewrite H; subst n.
+ destruct (e#r2); simpl; auto. rewrite Float32.mul2_add; auto.
+ rewrite Float32.mul_commut; auto.
+ simpl. econstructor; split; eauto.
+Qed.
+
+Lemma make_zext_correct:
+ forall s r x,
+ vmatch bc e#r x ->
+ let (op, args) := make_zext s r x in
+ exists v, eval_operation ge (Vptr sp Ptrofs.zero) op e##args m = Some v /\ Val.lessdef (Val.zero_ext s e#r) v.
+Proof.
+ intros; unfold make_zext. destruct (vincl x (Uns Ptop s)) eqn:INCL.
+- exists e#r; split; auto.
+ assert (V: vmatch bc e#r (Uns Ptop s)).
+ { eapply vmatch_ge; eauto. apply vincl_ge; auto. }
+ inv V; simpl; auto. rewrite is_uns_zero_ext in H4 by auto. rewrite H4; auto.
+- econstructor; split; simpl; eauto.
+Qed.
+
+Lemma make_sext_correct:
+ forall s r x,
+ vmatch bc e#r x ->
+ let (op, args) := make_sext s r x in
+ exists v, eval_operation ge (Vptr sp Ptrofs.zero) op e##args m = Some v /\ Val.lessdef (Val.sign_ext s e#r) v.
+Proof.
+ intros; unfold make_sext. destruct (vincl x (Sgn Ptop s)) eqn:INCL.
+- exists e#r; split; auto.
+ assert (V: vmatch bc e#r (Sgn Ptop s)).
+ { eapply vmatch_ge; eauto. apply vincl_ge; auto. }
+ inv V; simpl; auto. rewrite is_sgn_sign_ext in H4 by auto. rewrite H4; auto.
+- econstructor; split; simpl; eauto.
+Qed.
+
+Lemma op_strength_reduction_correct:
+ forall op args vl v,
+ vl = map (fun r => AE.get r ae) args ->
+ eval_operation ge (Vptr sp Ptrofs.zero) op e##args m = Some v ->
+ let (op', args') := op_strength_reduction op args vl in
+ exists w, eval_operation ge (Vptr sp Ptrofs.zero) op' e##args' m = Some w /\ Val.lessdef v w.
+Proof.
+ intros until v; unfold op_strength_reduction;
+ case (op_strength_reduction_match op args vl); simpl; intros.
+- (* add 1 *)
+ rewrite Val.add_commut in H0. InvApproxRegs; SimplVM; inv H0. apply make_addimm_correct; auto.
+- (* add 2 *)
+ InvApproxRegs; SimplVM; inv H0. apply make_addimm_correct; auto.
+- (* addshift *)
+ InvApproxRegs; SimplVM; inv H0. rewrite eval_static_shift_correct. apply make_addimm_correct; auto.
+- (* sub *)
+ InvApproxRegs; SimplVM; inv H0. rewrite Val.sub_add_opp. apply make_addimm_correct; auto.
+- (* subshift *)
+ InvApproxRegs; SimplVM; inv H0. rewrite eval_static_shift_correct, Val.sub_add_opp. apply make_addimm_correct; auto.
+- (* mul 1 *)
+ rewrite Val.mul_commut in H0. InvApproxRegs; SimplVM; inv H0. apply make_mulimm_correct; auto.
+- (* mul 2*)
+ InvApproxRegs; SimplVM; inv H0. apply make_mulimm_correct; auto.
+- (* divs *)
+ assert (e#r2 = Vint n2). clear H0. InvApproxRegs; SimplVM; auto.
+ apply make_divimm_correct; auto.
+- (* divu *)
+ assert (e#r2 = Vint n2). clear H0. InvApproxRegs; SimplVM; auto.
+ apply make_divuimm_correct; auto.
+- (* and 1 *)
+ rewrite Val.and_commut in H0. InvApproxRegs; SimplVM; inv H0. apply make_andimm_correct; auto.
+- (* and 2 *)
+ InvApproxRegs; SimplVM; inv H0. apply make_andimm_correct; auto.
+- (* andshift *)
+ InvApproxRegs; SimplVM; inv H0. rewrite eval_static_shift_correct. apply make_andimm_correct; auto.
+- (* andimm *)
+ inv H; inv H0. apply make_andimm_correct; auto.
+- (* or 1 *)
+ rewrite Val.or_commut in H0. InvApproxRegs; SimplVM; inv H0. apply make_orimm_correct; auto.
+- (* or 2 *)
+ InvApproxRegs; SimplVM; inv H0. apply make_orimm_correct; auto.
+- (* orshift *)
+ InvApproxRegs; SimplVM; inv H0. rewrite eval_static_shift_correct. apply make_orimm_correct; auto.
+- (* xor 1 *)
+ rewrite Val.xor_commut in H0. InvApproxRegs; SimplVM; inv H0. apply make_xorimm_correct; auto.
+- (* xor 2 *)
+ InvApproxRegs; SimplVM; inv H0. apply make_xorimm_correct; auto.
+- (* xorshift *)
+ InvApproxRegs; SimplVM; inv H0. rewrite eval_static_shift_correct. apply make_xorimm_correct; auto.
+- (* bic *)
+ InvApproxRegs; SimplVM; inv H0. apply make_andimm_correct; auto.
+- (* bicshift *)
+ InvApproxRegs; SimplVM; inv H0. rewrite eval_static_shift_correct. apply make_andimm_correct; auto.
+- (* orn *)
+ InvApproxRegs; SimplVM; inv H0. apply make_orimm_correct; auto.
+- (* ornshift *)
+ InvApproxRegs; SimplVM; inv H0. rewrite eval_static_shift_correct. apply make_orimm_correct; auto.
+- (* eor *)
+ InvApproxRegs; SimplVM; inv H0. apply make_xorimm_correct; auto.
+- (* eorshift *)
+ InvApproxRegs; SimplVM; inv H0. rewrite eval_static_shift_correct. apply make_xorimm_correct; auto.
+- (* shl *)
+ InvApproxRegs; SimplVM; inv H0. apply make_shlimm_correct; auto.
+- (* shr *)
+ InvApproxRegs; SimplVM; inv H0. apply make_shrimm_correct; auto.
+- (* shru *)
+ InvApproxRegs; SimplVM; inv H0. apply make_shruimm_correct; auto.
+- (* zext *)
+ InvApproxRegs; SimplVM; inv H0. apply make_zext_correct; auto.
+- (* sext *)
+ InvApproxRegs; SimplVM; inv H0. apply make_sext_correct; auto.
+- (* addl 1 *)
+ rewrite Val.addl_commut in H0. InvApproxRegs; SimplVM; inv H0. apply make_addlimm_correct; auto.
+- (* addl 2 *)
+ InvApproxRegs; SimplVM; inv H0. apply make_addlimm_correct; auto.
+- (* addshift *)
+ InvApproxRegs; SimplVM; inv H0. rewrite eval_static_shiftl_correct. apply make_addlimm_correct; auto.
+- (* addext *)
+ InvApproxRegs; SimplVM; inv H0. rewrite eval_static_extend_correct. apply make_addlimm_correct; auto.
+- (* subl *)
+ InvApproxRegs; SimplVM; inv H0. rewrite Val.subl_addl_opp. apply make_addlimm_correct; auto.
+- (* sublshift *)
+ InvApproxRegs; SimplVM; inv H0. rewrite eval_static_shiftl_correct, Val.subl_addl_opp. apply make_addlimm_correct; auto.
+- (* sublextend *)
+ InvApproxRegs; SimplVM; inv H0. rewrite eval_static_extend_correct, Val.subl_addl_opp. apply make_addlimm_correct; auto.
+- (* mull 1 *)
+ rewrite Val.mull_commut in H0. InvApproxRegs; SimplVM; inv H0. apply make_mullimm_correct; auto.
+- (* mull 2 *)
+ InvApproxRegs; SimplVM; inv H0. apply make_mullimm_correct; auto.
+- (* divl *)
+ assert (e#r2 = Vlong n2). clear H0. InvApproxRegs; SimplVM; auto.
+ apply make_divlimm_correct; auto.
+- (* divlu *)
+ assert (e#r2 = Vlong n2). clear H0. InvApproxRegs; SimplVM; auto.
+ apply make_divluimm_correct; auto.
+- (* andl 1 *)
+ rewrite Val.andl_commut in H0. InvApproxRegs; SimplVM; inv H0. apply make_andlimm_correct; auto.
+- (* andl 2 *)
+ InvApproxRegs; SimplVM; inv H0. apply make_andlimm_correct; auto.
+- (* andlshift *)
+ InvApproxRegs; SimplVM; inv H0. rewrite eval_static_shiftl_correct. apply make_andlimm_correct; auto.
+- (* andlimm *)
+ inv H; inv H0. apply make_andlimm_correct; auto.
+- (* orl 1 *)
+ rewrite Val.orl_commut in H0. InvApproxRegs; SimplVM; inv H0. apply make_orlimm_correct; auto.
+- (* orl 2 *)
+ InvApproxRegs; SimplVM; inv H0. apply make_orlimm_correct; auto.
+- (* orlshift *)
+ InvApproxRegs; SimplVM; inv H0. rewrite eval_static_shiftl_correct. apply make_orlimm_correct; auto.
+- (* xorl 1 *)
+ rewrite Val.xorl_commut in H0. InvApproxRegs; SimplVM; inv H0. apply make_xorlimm_correct; auto.
+- (* xorl 2 *)
+ InvApproxRegs; SimplVM; inv H0. apply make_xorlimm_correct; auto.
+- (* xorlshift *)
+ InvApproxRegs; SimplVM; inv H0. rewrite eval_static_shiftl_correct. apply make_xorlimm_correct; auto.
+- (* bicl *)
+ InvApproxRegs; SimplVM; inv H0. apply make_andlimm_correct; auto.
+- (* biclshift *)
+ InvApproxRegs; SimplVM; inv H0. rewrite eval_static_shiftl_correct. apply make_andlimm_correct; auto.
+- (* ornl *)
+ InvApproxRegs; SimplVM; inv H0. apply make_orlimm_correct; auto.
+- (* ornlshift *)
+ InvApproxRegs; SimplVM; inv H0. rewrite eval_static_shiftl_correct. apply make_orlimm_correct; auto.
+- (* eorl *)
+ InvApproxRegs; SimplVM; inv H0. apply make_xorlimm_correct; auto.
+- (* eorlshift *)
+ InvApproxRegs; SimplVM; inv H0. rewrite eval_static_shiftl_correct. apply make_xorlimm_correct; auto.
+- (* shll *)
+ InvApproxRegs; SimplVM; inv H0. apply make_shllimm_correct; auto.
+- (* shrl *)
+ InvApproxRegs; SimplVM; inv H0. apply make_shrlimm_correct; auto.
+- (* shrlu *)
+ InvApproxRegs; SimplVM; inv H0. apply make_shrluimm_correct; auto.
+- (* cond *)
+ inv H0. apply make_cmp_correct; auto.
+- (* select *)
+ inv H0. apply make_select_correct; congruence.
+- (* mulf 1 *)
+ InvApproxRegs; SimplVM; inv H0. rewrite <- H2. apply make_mulfimm_correct; auto.
+- (* mulf 2 *)
+ InvApproxRegs; SimplVM; inv H0. fold (Val.mulf (Vfloat n1) e#r2).
+ rewrite <- H2. apply make_mulfimm_correct_2; auto.
+- (* mulfs 1 *)
+ InvApproxRegs; SimplVM; inv H0. rewrite <- H2. apply make_mulfsimm_correct; auto.
+- (* mulfs 2 *)
+ InvApproxRegs; SimplVM; inv H0. fold (Val.mulfs (Vsingle n1) e#r2).
+ rewrite <- H2. apply make_mulfsimm_correct_2; auto.
+- (* default *)
+ exists v; auto.
+Qed.
+
+Lemma addr_strength_reduction_correct:
+ forall addr args vl res,
+ vl = map (fun r => AE.get r ae) args ->
+ eval_addressing ge (Vptr sp Ptrofs.zero) addr e##args = Some res ->
+ let (addr', args') := addr_strength_reduction addr args vl in
+ exists res', eval_addressing ge (Vptr sp Ptrofs.zero) addr' e##args' = Some res' /\ Val.lessdef res res'.
+Proof.
+ intros until res. unfold addr_strength_reduction.
+ destruct (addr_strength_reduction_match addr args vl); simpl;
+ intros VL EA; InvApproxRegs; SimplVM; try (inv EA).
+- econstructor; split; eauto. inv H0; simpl; auto. rewrite H2.
+ unfold Genv.symbol_address. destruct (Genv.find_symbol ge symb); auto.
+- rewrite Ptrofs.add_zero_l. econstructor; split; eauto.
+ inv H0; auto. rewrite H2; auto.
+- rewrite Ptrofs.add_zero_l. econstructor; split; eauto.
+ inv H; auto. rewrite H3; auto.
+- rewrite Ptrofs.add_zero_l. econstructor; split; eauto.
+ inv H0; auto. rewrite H3. rewrite Ptrofs.add_commut; auto.
+- econstructor; split; eauto. rewrite Val.addl_commut. auto.
+- econstructor; split; eauto.
+- rewrite Ptrofs.add_zero_l. rewrite a64_range. econstructor; split; eauto.
+ inv H; auto. rewrite H3; auto.
+- rewrite a64_range. econstructor; split; eauto.
+- rewrite Ptrofs.add_zero_l, eval_static_extend_correct.
+ econstructor; split; eauto. inv H; auto. rewrite H3; auto.
+- rewrite eval_static_extend_correct.
+ econstructor; split; eauto.
+- exists res; auto.
+Qed.
+
+End STRENGTH_REDUCTION.
diff --git a/aarch64/Conventions1.v b/aarch64/Conventions1.v
new file mode 100644
index 00000000..5914e8f2
--- /dev/null
+++ b/aarch64/Conventions1.v
@@ -0,0 +1,380 @@
+(* *********************************************************************)
+(* *)
+(* 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. *)
+(* *)
+(* *********************************************************************)
+
+(** Function calling conventions and other conventions regarding the use of
+ machine registers and stack slots. *)
+
+Require Import Coqlib Decidableplus.
+Require Import AST Events Locations.
+Require Archi.
+
+(** * Classification of machine registers *)
+
+(** Machine registers (type [mreg] in module [Locations]) are divided in:
+- Callee-save registers, whose value is preserved across a function call.
+- Caller-save registers that can be modified during a function call.
+
+ We follow the Procedure Call Standard for the ARM 64-bit Architecture
+ (AArch64) document: R19-R28 and F8-F15 are callee-save. *)
+
+Definition is_callee_save (r: mreg): bool :=
+ match r with
+ | R0 | R1 | R2 | R3 | R4 | R5 | R6 | R7 => false
+ | R8 | R9 | R10 | R11 | R12 | R13 | R14 | R15 => false
+ | R17 => false
+ | R19 | R20 | R21 | R22 | R23 => true
+ | R24 | R25 | R26 | R27 | R28 => true
+ | R29 => false
+ | F0 | F1 | F2 | F3 | F4 | F5 | F6 | F7 => false
+ | F8 | F9 | F10 | F11 | F12 | F13 | F14 | F15 => true
+ | F16 | F17 | F18 | F19 | F20 | F21 | F22 | F23 => false
+ | F24 | F25 | F26 | F27 | F28 | F29 | F30 | F31 => false
+ end.
+
+Definition int_caller_save_regs :=
+ R0 :: R1 :: R2 :: R3 :: R4 :: R5 :: R6 :: R7
+ :: R8 :: R9 :: R10 :: R11 :: R12 :: R13 :: R14 :: R15
+ :: R17 :: R29 :: nil.
+
+Definition float_caller_save_regs :=
+ F0 :: F1 :: F2 :: F3 :: F4 :: F5 :: F6 :: F7
+ :: F16 :: F17 :: F18 :: F19 :: F20 :: F21 :: F22 :: F23
+ :: F24 :: F25 :: F26 :: F27 :: F28 :: F29 :: F30 :: F31 :: nil.
+
+Definition int_callee_save_regs :=
+ R19 :: R20 :: R21 :: R22 :: R23
+ :: R24 :: R25 :: R26 :: R27 :: R28 :: nil.
+
+Definition float_callee_save_regs :=
+ F8 :: F9 :: F10 :: F11 :: F12 :: F13 :: F14 :: F15 :: nil.
+
+Definition destroyed_at_call :=
+ List.filter (fun r => negb (is_callee_save r)) all_mregs.
+
+Definition dummy_int_reg := R0. (**r Used in [Coloring]. *)
+Definition dummy_float_reg := F0. (**r Used in [Coloring]. *)
+
+Definition callee_save_type := mreg_type.
+
+Definition is_float_reg (r: mreg): bool :=
+ match r with
+ | R0 | R1 | R2 | R3 | R4 | R5 | R6 | R7
+ | R8 | R9 | R10 | R11 | R12 | R13 | R14 | R15
+ | R17 | R19 | R20 | R21 | R22 | R23
+ | R24 | R25 | R26 | R27 | R28
+ | R29 => false
+ | F0 | F1 | F2 | F3 | F4 | F5 | F6 | F7
+ | F8 | F9 | F10 | F11 | F12 | F13 | F14 | F15
+ | F16 | F17 | F18 | F19 | F20 | F21 | F22 | F23
+ | F24 | F25 | F26 | F27 | F28 | F29 | F30 | F31 => true
+ end.
+
+(** * Function calling conventions *)
+
+(** The functions in this section determine the locations (machine registers
+ and stack slots) used to communicate arguments and results between the
+ caller and the callee during function calls. These locations are functions
+ of the signature of the function and of the call instruction.
+ Agreement between the caller and the callee on the locations to use
+ is guaranteed by our dynamic semantics for Cminor and RTL, which demand
+ that the signature of the call instruction is identical to that of the
+ called function.
+
+ Calling conventions are largely arbitrary: they must respect the properties
+ proved in this section (such as no overlapping between the locations
+ of function arguments), but this leaves much liberty in choosing actual
+ locations. *)
+
+(** ** Location of function result *)
+
+(** The result value of a function is passed back to the caller in
+ registers [R0] or [F0], depending on the type of the
+ returned value. We treat a function without result as a function
+ with one integer result. *)
+
+Definition loc_result (s: signature) : rpair mreg :=
+ match s.(sig_res) with
+ | None => One R0
+ | Some (Tint | Tlong | Tany32 | Tany64) => One R0
+ | Some (Tfloat | Tsingle) => One F0
+ end.
+
+(** The result registers have types compatible with that given in the signature. *)
+
+Lemma loc_result_type:
+ forall sig,
+ subtype (proj_sig_res sig) (typ_rpair mreg_type (loc_result sig)) = true.
+Proof.
+ intros. unfold proj_sig_res, loc_result. destruct (sig_res sig) as [[]|]; auto.
+Qed.
+
+(** The result locations are caller-save registers *)
+
+Lemma loc_result_caller_save:
+ forall (s: signature),
+ forall_rpair (fun r => is_callee_save r = false) (loc_result s).
+Proof.
+ intros.
+ unfold loc_result. destruct (sig_res s) as [[]|]; simpl; auto.
+Qed.
+
+(** If the result is in a pair of registers, those registers are distinct and have type [Tint] at least. *)
+
+Lemma loc_result_pair:
+ forall sg,
+ match loc_result sg with
+ | One _ => True
+ | Twolong r1 r2 =>
+ r1 <> r2 /\ sg.(sig_res) = Some Tlong
+ /\ subtype Tint (mreg_type r1) = true /\ subtype Tint (mreg_type r2) = true
+ /\ Archi.ptr64 = false
+ end.
+Proof.
+ intros; unfold loc_result; destruct (sig_res sg) as [[]|]; exact I.
+Qed.
+
+(** The location of the result depends only on the result part of the signature *)
+
+Lemma loc_result_exten:
+ forall s1 s2, s1.(sig_res) = s2.(sig_res) -> loc_result s1 = loc_result s2.
+Proof.
+ intros. unfold loc_result. rewrite H; auto.
+Qed.
+
+(** ** Location of function arguments *)
+
+(**
+- The first 8 integer arguments are passed in registers [R0...R7].
+- The first 8 FP arguments are passed in registers [F0...F7].
+- Extra arguments are passed on the stack, in [Outgoing] slots of size
+ 64 bits (2 words), consecutively assigned, starting at word offset 0.
+**)
+
+Definition int_param_regs :=
+ R0 :: R1 :: R2 :: R3 :: R4 :: R5 :: R6 :: R7 :: nil.
+
+Definition float_param_regs :=
+ F0 :: F1 :: F2 :: F3 :: F4 :: F5 :: F6 :: F7 :: nil.
+
+Fixpoint loc_arguments_rec
+ (tyl: list typ) (ir fr ofs: Z) {struct tyl} : list (rpair loc) :=
+ match tyl with
+ | nil => nil
+ | (Tint | Tlong | Tany32 | Tany64) as ty :: tys =>
+ match list_nth_z int_param_regs ir with
+ | None =>
+ One (S Outgoing ofs ty) :: loc_arguments_rec tys ir fr (ofs + 2)
+ | Some ireg =>
+ One (R ireg) :: loc_arguments_rec tys (ir + 1) fr ofs
+ end
+ | (Tfloat | Tsingle) as ty :: tys =>
+ match list_nth_z float_param_regs fr with
+ | None =>
+ One (S Outgoing ofs ty) :: loc_arguments_rec tys ir fr (ofs + 2)
+ | Some freg =>
+ One (R freg) :: loc_arguments_rec tys ir (fr + 1) ofs
+ end
+ end.
+
+(** [loc_arguments s] returns the list of locations where to store arguments
+ when calling a function with signature [s]. *)
+
+Definition loc_arguments (s: signature) : list (rpair loc) :=
+ loc_arguments_rec s.(sig_args) 0 0 0.
+
+(** [size_arguments s] returns the number of [Outgoing] slots used
+ to call a function with signature [s]. *)
+
+Fixpoint size_arguments_rec (tyl: list typ) (ir fr ofs: Z) {struct tyl} : Z :=
+ match tyl with
+ | nil => ofs
+ | (Tint | Tlong | Tany32 | Tany64) :: tys =>
+ match list_nth_z int_param_regs ir with
+ | None => size_arguments_rec tys ir fr (ofs + 2)
+ | Some ireg => size_arguments_rec tys (ir + 1) fr ofs
+ end
+ | (Tfloat | Tsingle) :: tys =>
+ match list_nth_z float_param_regs fr with
+ | None => size_arguments_rec tys ir fr (ofs + 2)
+ | Some freg => size_arguments_rec tys ir (fr + 1) ofs
+ end
+ end.
+
+Definition size_arguments (s: signature) : Z :=
+ size_arguments_rec s.(sig_args) 0 0 0.
+
+(** Argument locations are either caller-save registers or [Outgoing]
+ stack slots at nonnegative offsets. *)
+
+Definition loc_argument_acceptable (l: loc) : Prop :=
+ match l with
+ | R r => is_callee_save r = false
+ | S Outgoing ofs ty => ofs >= 0 /\ (typealign ty | ofs)
+ | _ => False
+ end.
+
+Definition loc_argument_charact (ofs: Z) (l: loc) : Prop :=
+ match l with
+ | R r => In r int_param_regs \/ In r float_param_regs
+ | S Outgoing ofs' ty => ofs' >= ofs /\ (2 | ofs')
+ | _ => False
+ end.
+
+Remark loc_arguments_rec_charact:
+ forall tyl ir fr ofs p,
+ In p (loc_arguments_rec tyl ir fr ofs) -> (2 | ofs) -> forall_rpair (loc_argument_charact ofs) p.
+Proof.
+ assert (X: forall ofs1 ofs2 l, loc_argument_charact ofs2 l -> ofs1 <= ofs2 -> loc_argument_charact ofs1 l).
+ { destruct l; simpl; intros; auto. destruct sl; auto. intuition omega. }
+ assert (Y: forall ofs1 ofs2 p, forall_rpair (loc_argument_charact ofs2) p -> ofs1 <= ofs2 -> forall_rpair (loc_argument_charact ofs1) p).
+ { destruct p; simpl; intuition eauto. }
+ assert (Z: forall ofs, (2 | ofs) -> (2 | ofs + 2)).
+ { intros. apply Z.divide_add_r; auto. apply Z.divide_refl. }
+Opaque list_nth_z.
+ induction tyl; simpl loc_arguments_rec; intros.
+- contradiction.
+- assert (A: forall ty, In p
+ match list_nth_z int_param_regs ir with
+ | Some ireg => One (R ireg) :: loc_arguments_rec tyl (ir + 1) fr ofs
+ | None => One (S Outgoing ofs ty) :: loc_arguments_rec tyl ir fr (ofs + 2)
+ end ->
+ forall_rpair (loc_argument_charact ofs) p).
+ { intros. destruct (list_nth_z int_param_regs ir) as [r|] eqn:E; destruct H1.
+ subst. left. eapply list_nth_z_in; eauto.
+ eapply IHtyl; eauto.
+ subst. split. omega. assumption.
+ eapply Y; eauto. omega. }
+ assert (B: forall ty, In p
+ match list_nth_z float_param_regs fr with
+ | Some ireg => One (R ireg) :: loc_arguments_rec tyl ir (fr + 1) ofs
+ | None => One (S Outgoing ofs ty) :: loc_arguments_rec tyl ir fr (ofs + 2)
+ end ->
+ forall_rpair (loc_argument_charact ofs) p).
+ { intros. destruct (list_nth_z float_param_regs fr) as [r|] eqn:E; destruct H1.
+ subst. right. eapply list_nth_z_in; eauto.
+ eapply IHtyl; eauto.
+ subst. split. omega. assumption.
+ eapply Y; eauto. omega. }
+ destruct a; eauto.
+Qed.
+
+Lemma loc_arguments_acceptable:
+ forall (s: signature) (p: rpair loc),
+ In p (loc_arguments s) -> forall_rpair loc_argument_acceptable p.
+Proof.
+ unfold loc_arguments; intros.
+ assert (A: forall r, In r int_param_regs -> is_callee_save r = false) by decide_goal.
+ assert (B: forall r, In r float_param_regs -> is_callee_save r = false) by decide_goal.
+ assert (X: forall l, loc_argument_charact 0 l -> loc_argument_acceptable l).
+ { unfold loc_argument_charact, loc_argument_acceptable.
+ destruct l as [r | [] ofs ty]; auto. intros [C|C]; auto.
+ intros [C D]. split; auto. apply Z.divide_trans with 2; auto.
+ exists (2 / typealign ty); destruct ty; reflexivity.
+ }
+ exploit loc_arguments_rec_charact; eauto using Z.divide_0_r.
+ unfold forall_rpair; destruct p; intuition auto.
+Qed.
+
+Hint Resolve loc_arguments_acceptable: locs.
+
+(** The offsets of [Outgoing] arguments are below [size_arguments s]. *)
+
+Remark size_arguments_rec_above:
+ forall tyl ir fr ofs0,
+ ofs0 <= size_arguments_rec tyl ir fr ofs0.
+Proof.
+ induction tyl; simpl; intros.
+ omega.
+ assert (A: ofs0 <=
+ match list_nth_z int_param_regs ir with
+ | Some _ => size_arguments_rec tyl (ir + 1) fr ofs0
+ | None => size_arguments_rec tyl ir fr (ofs0 + 2)
+ end).
+ { destruct (list_nth_z int_param_regs ir); eauto.
+ apply Z.le_trans with (ofs0 + 2); auto. omega. }
+ assert (B: ofs0 <=
+ match list_nth_z float_param_regs fr with
+ | Some _ => size_arguments_rec tyl ir (fr + 1) ofs0
+ | None => size_arguments_rec tyl ir fr (ofs0 + 2)
+ end).
+ { destruct (list_nth_z float_param_regs fr); eauto.
+ apply Z.le_trans with (ofs0 + 2); auto. omega. }
+ destruct a; auto.
+Qed.
+
+Lemma size_arguments_above:
+ forall s, size_arguments s >= 0.
+Proof.
+ intros; unfold size_arguments. apply Z.le_ge. apply size_arguments_rec_above.
+Qed.
+
+Lemma loc_arguments_rec_bounded:
+ forall ofs ty tyl ir fr ofs0,
+ In (S Outgoing ofs ty) (regs_of_rpairs (loc_arguments_rec tyl ir fr ofs0)) ->
+ ofs + typesize ty <= size_arguments_rec tyl ir fr ofs0.
+Proof.
+ induction tyl; simpl; intros.
+- contradiction.
+- assert (T: forall ty0, typesize ty0 <= 2).
+ { destruct ty0; simpl; omega. }
+ assert (A: forall ty0,
+ In (S Outgoing ofs ty) (regs_of_rpairs
+ match list_nth_z int_param_regs ir with
+ | Some ireg =>
+ One (R ireg) :: loc_arguments_rec tyl (ir + 1) fr ofs0
+ | None => One (S Outgoing ofs0 ty0) :: loc_arguments_rec tyl ir fr (ofs0 + 2)
+ end) ->
+ ofs + typesize ty <=
+ match list_nth_z int_param_regs ir with
+ | Some _ => size_arguments_rec tyl (ir + 1) fr ofs0
+ | None => size_arguments_rec tyl ir fr (ofs0 + 2)
+ end).
+ { intros. destruct (list_nth_z int_param_regs ir); simpl in H0; destruct H0.
+ - discriminate.
+ - eapply IHtyl; eauto.
+ - inv H0. apply Z.le_trans with (ofs + 2). specialize (T ty). omega. apply size_arguments_rec_above.
+ - eapply IHtyl; eauto. }
+ assert (B: forall ty0,
+ In (S Outgoing ofs ty) (regs_of_rpairs
+ match list_nth_z float_param_regs fr with
+ | Some ireg =>
+ One (R ireg) :: loc_arguments_rec tyl ir (fr + 1) ofs0
+ | None => One (S Outgoing ofs0 ty0) :: loc_arguments_rec tyl ir fr (ofs0 + 2)
+ end) ->
+ ofs + typesize ty <=
+ match list_nth_z float_param_regs fr with
+ | Some _ => size_arguments_rec tyl ir (fr + 1) ofs0
+ | None => size_arguments_rec tyl ir fr (ofs0 + 2)
+ end).
+ { intros. destruct (list_nth_z float_param_regs fr); simpl in H0; destruct H0.
+ - discriminate.
+ - eapply IHtyl; eauto.
+ - inv H0. apply Z.le_trans with (ofs + 2). specialize (T ty). omega. apply size_arguments_rec_above.
+ - eapply IHtyl; eauto. }
+ destruct a; eauto.
+Qed.
+
+Lemma loc_arguments_bounded:
+ forall (s: signature) (ofs: Z) (ty: typ),
+ In (S Outgoing ofs ty) (regs_of_rpairs (loc_arguments s)) ->
+ ofs + typesize ty <= size_arguments s.
+Proof.
+ unfold loc_arguments, size_arguments; intros.
+ eauto using loc_arguments_rec_bounded.
+Qed.
+
+Lemma loc_arguments_main:
+ loc_arguments signature_main = nil.
+Proof.
+ unfold loc_arguments; reflexivity.
+Qed.
+
diff --git a/aarch64/Machregs.v b/aarch64/Machregs.v
new file mode 100644
index 00000000..b2a2308e
--- /dev/null
+++ b/aarch64/Machregs.v
@@ -0,0 +1,210 @@
+(* *********************************************************************)
+(* *)
+(* 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. *)
+(* *)
+(* *********************************************************************)
+
+Require Import String.
+Require Import Coqlib Decidableplus Maps.
+Require Import AST Op.
+
+(** ** Machine registers *)
+
+(** Integer register 16 is reserved as temporary and for call veeners.
+ Integer register 18 is reserved as the platform register.
+ Integer register 30 is reserved for the return address. *)
+
+Inductive mreg: Type :=
+ (** Allocatable integer regs *)
+ | R0 | R1 | R2 | R3 | R4 | R5 | R6 | R7
+ | R8 | R9 | R10 | R11 | R12 | R13 | R14 | R15
+ | R17 | R19 | R20 | R21 | R22 | R23
+ | R24 | R25 | R26 | R27 | R28 | R29
+ (** Allocatable floating-point regs *)
+ | F0 | F1 | F2 | F3 | F4 | F5 | F6 | F7
+ | F8 | F9 | F10 | F11 | F12 | F13 | F14 | F15
+ | F16 | F17 | F18 | F19 | F20 | F21 | F22 | F23
+ | F24 | F25 | F26 | F27 | F28 | F29 | F30 | F31.
+
+Lemma mreg_eq: forall (r1 r2: mreg), {r1 = r2} + {r1 <> r2}.
+Proof. decide equality. Defined.
+Global Opaque mreg_eq.
+
+Definition all_mregs :=
+ R0 :: R1 :: R2 :: R3 :: R4 :: R5 :: R6 :: R7
+ :: R8 :: R9 :: R10 :: R11 :: R12 :: R13 :: R14 :: R15
+ :: R17 :: R19 :: R20 :: R21 :: R22 :: R23
+ :: R24 :: R25 :: R26 :: R27 :: R28 :: R29
+ :: F0 :: F1 :: F2 :: F3 :: F4 :: F5 :: F6 :: F7
+ :: F8 :: F9 :: F10 :: F11 :: F12 :: F13 :: F14 :: F15
+ :: F16 :: F17 :: F18 :: F19 :: F20 :: F21 :: F22 :: F23
+ :: F24 :: F25 :: F26 :: F27 :: F28 :: F29 :: F30 :: F31
+ :: nil.
+
+Lemma all_mregs_complete:
+ forall (r: mreg), In r all_mregs.
+Proof.
+ assert (forall r, proj_sumbool (In_dec mreg_eq r all_mregs) = true) by (destruct r; reflexivity).
+ intros. specialize (H r). InvBooleans. auto.
+Qed.
+
+Instance Decidable_eq_mreg : forall (x y: mreg), Decidable (eq x y) := Decidable_eq mreg_eq.
+
+Instance Finite_mreg : Finite mreg := {
+ Finite_elements := all_mregs;
+ Finite_elements_spec := all_mregs_complete
+}.
+
+Definition mreg_type (r: mreg): typ := Tany64.
+
+Open Scope positive_scope.
+
+Module IndexedMreg <: INDEXED_TYPE.
+ Definition t := mreg.
+ Definition eq := mreg_eq.
+ Definition index (r: mreg): positive :=
+ match r with
+ | R0 => 1 | R1 => 2 | R2 => 3 | R3 => 4
+ | R4 => 5 | R5 => 6 | R6 => 7 | R7 => 8
+ | R8 => 9 | R9 => 10 | R10 => 11 | R11 => 12
+ | R12 => 13 | R13 => 14 | R14 => 15 | R15 => 16
+ | R17 => 17 | R19 => 19
+ | R20 => 20 | R21 => 21 | R22 => 22 | R23 => 23
+ | R24 => 24 | R25 => 25 | R26 => 26 | R27 => 27
+ | R28 => 28 | R29 => 29
+ | F0 => 32 | F1 => 33 | F2 => 34 | F3 => 35
+ | F4 => 36 | F5 => 37 | F6 => 38 | F7 => 39
+ | F8 => 40 | F9 => 41 | F10 => 42 | F11 => 43
+ | F12 => 44 | F13 => 45 | F14 => 46 | F15 => 47
+ | F16 => 48 | F17 => 49 | F18 => 50 | F19 => 51
+ | F20 => 52 | F21 => 53 | F22 => 54 | F23 => 55
+ | F24 => 56 | F25 => 57 | F26 => 58 | F27 => 59
+ | F28 => 60 | F29 => 61 | F30 => 62 | F31 => 63
+ end.
+ Lemma index_inj:
+ forall r1 r2, index r1 = index r2 -> r1 = r2.
+ Proof.
+ decide_goal.
+ Qed.
+End IndexedMreg.
+
+Definition is_stack_reg (r: mreg) : bool := false.
+
+(** ** Names of registers *)
+
+Local Open Scope string_scope.
+
+Definition register_names :=
+ ("X0", R0) :: ("X1", R1) :: ("X2", R2) :: ("X3", R3)
+ :: ("X4", R4) :: ("X5", R5) :: ("X6", R6) :: ("X7", R7)
+ :: ("X8", R8) :: ("X9", R9) :: ("X10", R10) :: ("X11", R11)
+ :: ("X12", R12) :: ("X13", R13) :: ("X14", R14) :: ("X15", R15)
+ :: ("X17", R17) :: ("X19", R19)
+ :: ("X20", R20) :: ("X21", R21) :: ("X22", R22) :: ("X23", R23)
+ :: ("X24", R24) :: ("X25", R25) :: ("X26", R26) :: ("X27", R27)
+ :: ("X28", R28) :: ("X29", R29)
+ :: ("D0", F0) :: ("D1", F1) :: ("D2", F2) :: ("D3", F3)
+ :: ("D4", F4) :: ("D5", F5) :: ("D6", F6) :: ("D7", F7)
+ :: ("D8", F8) :: ("D9", F9) :: ("D10", F10) :: ("D11", F11)
+ :: ("D12", F12) :: ("D13", F13) :: ("D14", F14) :: ("D15", F15)
+ :: ("D16", F16) :: ("D17", F17) :: ("D18", F18) :: ("D19", F19)
+ :: ("D20", F20) :: ("D21", F21) :: ("D22", F22) :: ("D23", F23)
+ :: ("D24", F24) :: ("D25", F25) :: ("D26", F26) :: ("D27", F27)
+ :: ("D28", F28) :: ("D29", F29) :: ("D30", F30) :: ("D31", F31)
+ :: nil.
+
+Definition register_by_name (s: string) : option mreg :=
+ let fix assoc (l: list (string * mreg)) : option mreg :=
+ match l with
+ | nil => None
+ | (s1, r1) :: l' => if string_dec s s1 then Some r1 else assoc l'
+ end
+ in assoc register_names.
+
+(** ** Destroyed registers, preferred registers *)
+
+Definition destroyed_by_op (op: operation): list mreg :=
+ match op with
+ | Oshrximm _ | Oshrlximm _ => R17 :: nil
+ | _ => nil
+ end.
+
+Definition destroyed_by_load (chunk: memory_chunk) (addr: addressing): list mreg :=
+ nil.
+
+Definition destroyed_by_store (chunk: memory_chunk) (addr: addressing): list mreg := nil.
+
+Definition destroyed_by_cond (cond: condition): list mreg := nil.
+
+Definition destroyed_by_jumptable: list mreg := R17 :: nil.
+
+Fixpoint destroyed_by_clobber (cl: list string): list mreg :=
+ match cl with
+ | nil => nil
+ | c1 :: cl =>
+ match register_by_name c1 with
+ | Some r => r :: destroyed_by_clobber cl
+ | None => destroyed_by_clobber cl
+ end
+ end.
+
+Definition destroyed_by_builtin (ef: external_function): list mreg :=
+ match ef with
+ | EF_memcpy sz al => R15 :: R17 :: R29 :: nil
+ | EF_inline_asm txt sg clob => destroyed_by_clobber clob
+ | _ => nil
+ end.
+
+Definition destroyed_by_setstack (ty: typ): list mreg := nil.
+
+Definition destroyed_at_function_entry: list mreg := R29 :: nil.
+
+Definition destroyed_at_indirect_call: list mreg := nil.
+
+Definition temp_for_parent_frame: mreg := R29.
+
+Definition mregs_for_operation (op: operation): list (option mreg) * option mreg :=
+ (nil, None).
+
+Definition mregs_for_builtin (ef: external_function): list (option mreg) * list(option mreg) :=
+ (nil, nil).
+
+Global Opaque
+ destroyed_by_op destroyed_by_load destroyed_by_store
+ destroyed_by_cond destroyed_by_jumptable destroyed_by_builtin
+ destroyed_by_setstack destroyed_at_function_entry temp_for_parent_frame
+ destroyed_at_indirect_call
+ mregs_for_operation mregs_for_builtin.
+
+(** Two-address operations. Return [true] if the first argument and
+ the result must be in the same location *and* are unconstrained
+ by [mregs_for_operation]. There is one for AArch64: [Olowlong],
+ which is actually a no-operation in the generated asm code. *)
+
+Definition two_address_op (op: operation) : bool :=
+ match op with
+ | Olowlong => true
+ | _ => false
+ end.
+
+Global Opaque two_address_op.
+
+(* Constraints on constant propagation for builtins *)
+
+Definition builtin_constraints (ef: external_function) :
+ list builtin_arg_constraint :=
+ match ef with
+ | EF_vload _ => OK_addressing :: nil
+ | EF_vstore _ => OK_addressing :: OK_default :: nil
+ | EF_memcpy _ _ => OK_addrstack :: OK_addrstack :: nil
+ | EF_annot kind txt targs => map (fun _ => OK_all) targs
+ | EF_debug kind txt targs => map (fun _ => OK_all) targs
+ | _ => nil
+ end.
+
diff --git a/aarch64/Machregsaux.ml b/aarch64/Machregsaux.ml
new file mode 100644
index 00000000..d7f10b9b
--- /dev/null
+++ b/aarch64/Machregsaux.ml
@@ -0,0 +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. *)
+(* *)
+(* *********************************************************************)
+
+(** Auxiliary functions on machine registers *)
+
+open Camlcoq
+open Machregs
+
+let register_names : (mreg, string) Hashtbl.t = Hashtbl.create 31
+
+let _ =
+ List.iter
+ (fun (s, r) -> Hashtbl.add register_names r (camlstring_of_coqstring s))
+ Machregs.register_names
+
+let is_scratch_register s =
+ s = "X16" || s = "x16" || s = "X30" || s = "x30"
+
+
+let name_of_register r =
+ try Some (Hashtbl.find register_names r) with Not_found -> None
+
+let register_by_name s =
+ Machregs.register_by_name (coqstring_uppercase_ascii_of_camlstring s)
+
+let can_reserve_register r = Conventions1.is_callee_save r
diff --git a/aarch64/NeedOp.v b/aarch64/NeedOp.v
new file mode 100644
index 00000000..8fcab9e1
--- /dev/null
+++ b/aarch64/NeedOp.v
@@ -0,0 +1,253 @@
+(* *********************************************************************)
+(* *)
+(* 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. *)
+(* *)
+(* *********************************************************************)
+
+Require Import Coqlib.
+Require Import AST Integers Floats.
+Require Import Values Memory Globalenvs.
+Require Import Op RTL.
+Require Import NeedDomain.
+
+(** Neededness analysis for AArch64 operators *)
+
+Definition needs_of_shift (s: shift) (a: amount32) (nv: nval) :=
+ match s with
+ | Slsl => shlimm nv a
+ | Sasr => shrimm nv a
+ | Slsr => shruimm nv a
+ | Sror => ror nv a
+ end.
+
+Definition zero_ext' (s: Z) (nv: nval) :=
+ if zle 0 s then zero_ext s nv else default nv.
+Definition sign_ext' (s: Z) (nv: nval) :=
+ if zlt 0 s then sign_ext s nv else default nv.
+
+Definition op1 (nv: nval) := nv :: nil.
+Definition op2 (nv: nval) := nv :: nv :: nil.
+Definition op1shift (s: shift) (a: amount32) (nv: nval) :=
+ needs_of_shift s a nv :: nil.
+Definition op2shift (s: shift) (a: amount32) (nv: nval) :=
+ nv :: needs_of_shift s a nv :: nil.
+
+Definition needs_of_condition (cond: condition): list nval := nil.
+
+Definition needs_of_operation (op: operation) (nv: nval): list nval :=
+ match op with
+ | Omove => nv :: nil
+ | Ointconst _ => nil
+ | Olongconst _ => nil
+ | Ofloatconst _ => nil
+ | Osingleconst _ => nil
+ | Oaddrsymbol _ _ => nil
+ | Oaddrstack _ => nil
+ | Oshift s a => op1shift s a nv
+ | Oadd | Osub | Omul => op2 (modarith nv)
+ | Oaddshift s a | Osubshift s a => op2shift s a (modarith nv)
+ | Oaddimm _ => op1 (modarith nv)
+ | Oneg => op1 (modarith nv)
+ | Onegshift s a => op1shift s a (modarith nv)
+ | Omuladd | Omulsub =>
+ let n := modarith nv in n :: n :: n :: nil
+ | Odiv | Odivu => op2 (default nv)
+ | Oand | Oor | Oxor => op2 (bitwise nv)
+ | Oandshift s a | Oorshift s a | Oxorshift s a => op2shift s a (bitwise nv)
+ | Oandimm n => op1 (andimm nv n)
+ | Oorimm n => op1 (orimm nv n)
+ | Oxorimm n => op1 (bitwise nv)
+ | Onot => op1 (bitwise nv)
+ | Onotshift s a => needs_of_shift s a (bitwise nv) :: nil
+ | Obic | Oorn | Oeqv =>
+ let n := bitwise nv in n :: bitwise n :: nil
+ | Obicshift s a | Oornshift s a | Oeqvshift s a =>
+ let n := bitwise nv in n :: needs_of_shift s a (bitwise n) :: nil
+ | Oshl | Oshr | Oshru => op2 (default nv)
+ | Oshrximm _ => op1 (default nv)
+ | Ozext s => op1 (zero_ext' s nv)
+ | Osext s => op1 (sign_ext' s nv)
+ | Oshlzext s a => op1 (zero_ext' s (shlimm nv a))
+ | Oshlsext s a => op1 (sign_ext' s (shlimm nv a))
+ | Ozextshr a s => op1 (shruimm (zero_ext' s nv) a)
+ | Osextshr a s => op1 (shrimm (sign_ext' s nv) a)
+
+ | Oshiftl _ _ | Oextend _ _ => op1 (default nv)
+ | Omakelong | Olowlong | Ohighlong => op1 (default nv)
+ | Oaddl | Osubl | Omull => op2 (default nv)
+ | Oaddlshift _ _ | Oaddlext _ _ | Osublshift _ _ | Osublext _ _ => op2 (default nv)
+ | Oaddlimm _ => op1 (default nv)
+ | Onegl => op1 (default nv)
+ | Oneglshift _ _ => op1 (default nv)
+ | Omulladd | Omullsub => let n := default nv in n :: n :: n :: nil
+ | Omullhs | Omullhu | Odivl | Odivlu => op2 (default nv)
+ | Oandl | Oorl | Oxorl | Obicl | Oornl | Oeqvl => op2 (default nv)
+ | Oandlshift _ _ | Oorlshift _ _ | Oxorlshift _ _
+ | Obiclshift _ _ | Oornlshift _ _ | Oeqvlshift _ _ => op2 (default nv)
+ | Oandlimm _ | Oorlimm _ | Oxorlimm _ => op1 (default nv)
+ | Onotl => op1 (default nv)
+ | Onotlshift _ _ => op1 (default nv)
+ | Oshll | Oshrl | Oshrlu => op2 (default nv)
+ | Oshrlximm _ => op1 (default nv)
+ | Ozextl _ | Osextl _
+ | Oshllzext _ _ | Oshllsext _ _ | Ozextshrl _ _ | Osextshrl _ _ => op1 (default nv)
+ | Onegf | Oabsf => op1 (default nv)
+ | Oaddf | Osubf | Omulf | Odivf => op2 (default nv)
+ | Onegfs | Oabsfs => op1 (default nv)
+ | Oaddfs | Osubfs | Omulfs | Odivfs => op2 (default nv)
+ | Ofloatofsingle | Osingleoffloat => op1 (default nv)
+ | Ointoffloat | Ointuoffloat | Ofloatofint | Ofloatofintu => op1 (default nv)
+ | Olongoffloat | Olonguoffloat | Ofloatoflong | Ofloatoflongu => op1 (default nv)
+ | Ointofsingle | Ointuofsingle | Osingleofint | Osingleofintu => op1 (default nv)
+ | Olongofsingle | Olonguofsingle | Osingleoflong | Osingleoflongu => op1 (default nv)
+ | Ocmp c => needs_of_condition c
+ | Osel c ty => nv :: nv :: needs_of_condition c
+ end.
+
+Definition operation_is_redundant (op: operation) (nv: nval): bool :=
+ match op with
+ | Ozext s => zle 0 s && zero_ext_redundant s nv
+ | Osext s => zlt 0 s && sign_ext_redundant s nv
+ | Oandimm n => andimm_redundant nv n
+ | Oorimm n => orimm_redundant nv n
+ | _ => false
+ end.
+
+Ltac InvAgree :=
+ match goal with
+ | [H: vagree_list nil _ _ |- _ ] => inv H; InvAgree
+ | [H: vagree_list (_::_) _ _ |- _ ] => inv H; InvAgree
+ | _ => idtac
+ end.
+
+Ltac TrivialExists :=
+ match goal with
+ | [ |- exists v, Some ?x = Some v /\ _ ] => exists x; split; auto
+ | _ => idtac
+ end.
+
+Lemma shift_sound:
+ forall v w s a x,
+ vagree v w (needs_of_shift s a x) ->
+ vagree (eval_shift s v a) (eval_shift s w a) x.
+Proof.
+ intros until x; destruct s; simpl; intros.
+- apply shlimm_sound; auto.
+- apply shruimm_sound; auto.
+- apply shrimm_sound; auto.
+- apply ror_sound; auto.
+Qed.
+
+Lemma zero_ext'_sound:
+ forall v w x n,
+ vagree v w (zero_ext' n x) ->
+ vagree (Val.zero_ext n v) (Val.zero_ext n w) x.
+Proof.
+ unfold zero_ext'; intros. destruct (zle 0 n).
+- apply zero_ext_sound; auto.
+- assert (E: x = Nothing \/ Val.lessdef v w) by (destruct x; auto).
+ destruct E. subst x; simpl; auto. apply vagree_lessdef; apply Val.zero_ext_lessdef; auto.
+Qed.
+
+Lemma sign_ext'_sound:
+ forall v w x n,
+ vagree v w (sign_ext' n x) ->
+ vagree (Val.sign_ext n v) (Val.sign_ext n w) x.
+Proof.
+ unfold sign_ext'; intros. destruct (zlt 0 n).
+- apply sign_ext_sound; auto.
+- assert (E: x = Nothing \/ Val.lessdef v w) by (destruct x; auto).
+ destruct E. subst x; simpl; auto. apply vagree_lessdef; apply Val.sign_ext_lessdef; auto.
+Qed.
+
+Section SOUNDNESS.
+
+Variable ge: genv.
+Variable sp: block.
+Variables m m': mem.
+Hypothesis PERM: forall b ofs k p, Mem.perm m b ofs k p -> Mem.perm m' b ofs k p.
+
+Lemma needs_of_condition_sound:
+ forall cond args b args',
+ eval_condition cond args m = Some b ->
+ vagree_list args args' (needs_of_condition cond) ->
+ eval_condition cond args' m' = Some b.
+Proof.
+ intros. unfold needs_of_condition in H0.
+ eapply default_needs_of_condition_sound; eauto.
+Qed.
+
+Lemma needs_of_operation_sound:
+ forall op args v nv args',
+ eval_operation ge (Vptr sp Ptrofs.zero) op args m = Some v ->
+ vagree_list args args' (needs_of_operation op nv) ->
+ nv <> Nothing ->
+ exists v',
+ eval_operation ge (Vptr sp Ptrofs.zero) op args' m' = Some v'
+ /\ vagree v v' nv.
+Proof.
+ unfold needs_of_operation; intros; destruct op; try (eapply default_needs_of_operation_sound; eauto; fail);
+ simpl in *; FuncInv; InvAgree; TrivialExists.
+- apply shift_sound; auto.
+- apply add_sound; auto.
+- apply add_sound; auto using shift_sound.
+- apply add_sound; auto with na.
+- apply neg_sound; auto.
+- apply neg_sound; auto using shift_sound.
+- apply sub_sound; auto.
+- apply sub_sound; auto using shift_sound.
+- apply mul_sound; auto.
+- apply add_sound; auto. apply mul_sound; rewrite modarith_idem; auto.
+- apply sub_sound; auto. apply mul_sound; rewrite modarith_idem; auto.
+- apply and_sound; auto.
+- apply and_sound; auto using shift_sound.
+- apply andimm_sound; auto.
+- apply or_sound; auto.
+- apply or_sound; auto using shift_sound.
+- apply orimm_sound; auto.
+- apply xor_sound; auto.
+- apply xor_sound; auto using shift_sound.
+- apply xor_sound; auto with na.
+- apply notint_sound; auto.
+- apply notint_sound; auto using shift_sound.
+- apply and_sound; auto. apply notint_sound; rewrite bitwise_idem; auto.
+- apply and_sound; auto. apply notint_sound; rewrite bitwise_idem; auto using shift_sound.
+- apply or_sound; auto. apply notint_sound; rewrite bitwise_idem; auto.
+- apply or_sound; auto. apply notint_sound; rewrite bitwise_idem; auto using shift_sound.
+- apply xor_sound; auto. apply notint_sound; rewrite bitwise_idem; auto.
+- apply xor_sound; auto. apply notint_sound; rewrite bitwise_idem; auto using shift_sound.
+- apply zero_ext'_sound; auto.
+- apply sign_ext'_sound; auto.
+- apply shlimm_sound; apply zero_ext'_sound; auto.
+- apply shlimm_sound; apply sign_ext'_sound; auto.
+- apply zero_ext'_sound; apply shruimm_sound; auto.
+- apply sign_ext'_sound; apply shrimm_sound; auto.
+- destruct (eval_condition cond args m) as [b|] eqn:EC.
+ erewrite needs_of_condition_sound by eauto.
+ apply select_sound; auto.
+ simpl; auto with na.
+Qed.
+
+Lemma operation_is_redundant_sound:
+ forall op nv arg1 args v arg1' args',
+ operation_is_redundant op nv = true ->
+ eval_operation ge (Vptr sp Ptrofs.zero) op (arg1 :: args) m = Some v ->
+ vagree_list (arg1 :: args) (arg1' :: args') (needs_of_operation op nv) ->
+ vagree v arg1' nv.
+Proof.
+ intros. destruct op; simpl in *; try discriminate; inv H1; FuncInv; subst.
+- apply andimm_redundant_sound; auto.
+- apply orimm_redundant_sound; auto.
+- InvBooleans. unfold zero_ext' in H5; rewrite zle_true in H5 by auto.
+ apply zero_ext_redundant_sound; auto.
+- InvBooleans. unfold sign_ext' in H5; rewrite zlt_true in H5 by auto.
+ apply sign_ext_redundant_sound; auto.
+Qed.
+
+End SOUNDNESS.
diff --git a/aarch64/Op.v b/aarch64/Op.v
new file mode 100644
index 00000000..34c03c77
--- /dev/null
+++ b/aarch64/Op.v
@@ -0,0 +1,1778 @@
+(* *********************************************************************)
+(* *)
+(* 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. *)
+(* *)
+(* *********************************************************************)
+
+(** Operators and addressing modes. The abstract syntax and dynamic
+ semantics for the CminorSel, RTL, LTL and Mach languages depend on the
+ following types, defined in this library:
+- [condition]: boolean conditions for conditional branches;
+- [operation]: arithmetic and logical operations;
+- [addressing]: addressing modes for load and store operations.
+
+ These types are processor-specific and correspond roughly to what the
+ processor can compute in one instruction. In other terms, these
+ types reflect the state of the program after instruction selection.
+ For a processor-independent set of operations, see the abstract
+ syntax and dynamic semantics of the Cminor language.
+*)
+
+Require Import Axioms Coqlib BoolEqual.
+Require Import AST Integers Floats Values Memory Globalenvs Events.
+
+Set Implicit Arguments.
+Local Transparent Archi.ptr64.
+
+(** Shift amounts *)
+
+Record amount32 : Type := {
+ a32_amount :> int;
+ a32_range : Int.ltu a32_amount Int.iwordsize = true }.
+
+Record amount64 : Type := {
+ a64_amount :> int;
+ a64_range : Int.ltu a64_amount Int64.iwordsize' = true }.
+
+(** Shifted operands *)
+
+Inductive shift : Type :=
+ | Slsl (**r left shift *)
+ | Slsr (**r right unsigned shift *)
+ | Sasr (**r right signed shift *)
+ | Sror. (**r rotate right *)
+
+(** Sign- or zero-extended operands *)
+
+Inductive extension : Type :=
+ | Xsgn32 (**r from signed 32-bit integer to 64-bit integer *)
+ | Xuns32. (**r from unsigned 32-bit integer to 64-bit integer *)
+
+(** Conditions (boolean-valued operators). *)
+
+Inductive condition: Type :=
+(** Tests over 32-bit integers *)
+ | Ccomp (c: comparison) (**r signed comparison *)
+ | Ccompu (c: comparison) (**r unsigned comparison *)
+ | Ccompimm (c: comparison) (n: int) (**r signed comparison with constant *)
+ | Ccompuimm (c: comparison) (n: int) (**r unsigned comparison with constant *)
+ | Ccompshift (c: comparison) (s: shift) (a: amount32) (**r signed comparison with shift *)
+ | Ccompushift (c: comparison) (s: shift) (a: amount32)(**r unsigned comparison width shift *)
+ | Cmaskzero (n: int) (**r test [(arg & n) == 0] *)
+ | Cmasknotzero (n: int) (**r test [(arg & n) != 0] *)
+(** Tests over 64-bit integers *)
+ | Ccompl (c: comparison) (**r signed comparison *)
+ | Ccomplu (c: comparison) (**r unsigned comparison *)
+ | Ccomplimm (c: comparison) (n: int64) (**r signed comparison with constant *)
+ | Ccompluimm (c: comparison) (n: int64) (**r unsigned comparison with constant *)
+ | Ccomplshift (c: comparison) (s: shift) (a: amount64)(**r signed comparison with shift *)
+ | Ccomplushift (c: comparison) (s: shift) (a: amount64)(**r unsigned comparison width shift *)
+ | Cmasklzero (n: int64) (**r test [(arg & n) == 0] *)
+ | Cmasklnotzero (n: int64) (**r test [(arg & n) != 0] *)
+(** Tests over 64-bit floating-point numbers *)
+ | Ccompf (c: comparison) (**r FP comparison *)
+ | Cnotcompf (c: comparison) (**r negation of an FP comparison *)
+ | Ccompfzero (c: comparison) (**r comparison with 0.0 *)
+ | Cnotcompfzero (c: comparison) (**r negation of comparison with 0.0 *)
+(** Tests over 32-bit floating-point numbers *)
+ | Ccompfs (c: comparison) (**r FP comparison *)
+ | Cnotcompfs (c: comparison) (**r negation of an FP comparison *)
+ | Ccompfszero (c: comparison) (**r equal to 0.0 *)
+ | Cnotcompfszero (c: comparison). (**r not equal to 0.0 *)
+
+(** Arithmetic and logical operations. In the descriptions, [rd] is the
+ result of the operation and [r1], [r2], etc, are the arguments. *)
+
+Inductive operation : Type :=
+ | Omove (**r [rd = r1] *)
+ | Ointconst (n: int) (**r [rd] is set to the given integer constant *)
+ | Olongconst (n: int64) (**r [rd] is set to the given integer constant *)
+ | Ofloatconst (n: float) (**r [rd] is set to the given float constant *)
+ | Osingleconst (n: float32) (**r [rd] is set to the given float constant *)
+ | Oaddrsymbol (id: ident) (ofs: ptrofs) (**r [rd] is set to the address of the symbol plus the given offset *)
+ | Oaddrstack (ofs: ptrofs) (**r [rd] is set to the stack pointer plus the given offset *)
+(** 32-bit integer arithmetic *)
+ | Oshift (s: shift) (a: amount32) (**r shift or rotate by immediate quantity *)
+ | Oadd (**r [rd = r1 + r2] *)
+ | Oaddshift (s: shift) (a: amount32) (**r [rd = r1 + shifted r2] *)
+ | Oaddimm (n: int) (**r [rd = r1 + n] *)
+ | Oneg (**r [rd = - r1] *)
+ | Onegshift (s: shift) (a: amount32) (**r [rd = - shifted r1] *)
+ | Osub (**r [rd = r1 - r2] *)
+ | Osubshift (s: shift) (a: amount32) (**r [rd = r1 - shifted r2] *)
+ | Omul (**r [rd = r1 * r2] *)
+ | Omuladd (**r [rd = r1 + r2 * r3] *)
+ | Omulsub (**r [rd = r1 - r2 * r3] *)
+ | Odiv (**r [rd = r1 / r2] (signed) *)
+ | Odivu (**r [rd = r1 / r2] (unsigned) *)
+ | Oand (**r [rd = r1 & r2] *)
+ | Oandshift (s: shift) (a: amount32) (**r [rd = r1 & shifted r2] *)
+ | Oandimm (n: int) (**r [rd = r1 & n] *)
+ | Oor (**r [rd = r1 | r2] *)
+ | Oorshift (s: shift) (a: amount32) (**r [rd = r1 | shifted r2] *)
+ | Oorimm (n: int) (**r [rd = r1 | n] *)
+ | Oxor (**r [rd = r1 ^ r2] *)
+ | Oxorshift (s: shift) (a: amount32) (**r [rd = r1 ^ shifted r2] *)
+ | Oxorimm (n: int) (**r [rd = r1 ^ n] *)
+ | Onot (**r [rd = ~r1] *)
+ | Onotshift (s: shift) (a: amount32) (**r [rd = ~ shifted r1] *)
+ | Obic (**r [rd = r1 & ~r2] *)
+ | Obicshift (s: shift) (a: amount32) (**r [rd = r1 ^ ~ shifted r2] *)
+ | Oorn (**r [rd = r1 | ~r2] *)
+ | Oornshift (s: shift) (a: amount32) (**r [rd = r1 | ~ shifted r2] *)
+ | Oeqv (**r [rd = r1 ^ ~r2] *)
+ | Oeqvshift (s: shift) (a: amount32) (**r [rd = r1 | ~ shifted r2] *)
+ | Oshl (**r [rd = r1 << r2] *)
+ | Oshr (**r [rd = r1 >> r2] (signed) *)
+ | Oshru (**r [rd = r1 >> r2] (unsigned) *)
+ | Oshrximm (n: int) (**r [rd = r1 / 2^n] (signed) *)
+ | Ozext (s: Z) (**r [rd = zero_ext(r1,s)] *)
+ | Osext (s: Z) (**r [rd = sign_ext(r1,s)] *)
+ | Oshlzext (s: Z) (a: amount32) (**r [rd = zero_ext(r1,s) << a] *)
+ | Oshlsext (s: Z) (a: amount32) (**r [rd = sign_ext(r1,s) << a] *)
+ | Ozextshr (a: amount32) (s: Z) (**r [rd = zero_ext(r1 >> a, s)] *)
+ | Osextshr (a: amount32) (s: Z) (**r [rd = sign_ext(r1 >> a, s)] *)
+(** 64-bit integer arithmetic *)
+ | Oshiftl (s: shift) (a: amount64) (**r shift or rotate by immediate quantity *)
+ | Oextend (x: extension) (a: amount64) (**r convert from 32 to 64 bits and shift *)
+ | Omakelong (**r [rd = r1 << 32 | r2] *)
+ | Olowlong (**r [rd = low-word(r1)] *)
+ | Ohighlong (**r [rd = high-word(r1)] *)
+ | Oaddl (**r [rd = r1 + r2] *)
+ | Oaddlshift (s: shift) (a: amount64) (**r [rd = r1 + shifted r2] *)
+ | Oaddlext (x: extension) (a: amount64) (**r [rd = r1 + shifted, converted r2] *)
+ | Oaddlimm (n: int64) (**r [rd = r1 + n] *)
+ | Onegl (**r [rd = - r1] *)
+ | Oneglshift (s: shift) (a: amount64) (**r [rd = - shifted r1] *)
+ | Osubl (**r [rd = r1 - r2] *)
+ | Osublshift (s: shift) (a: amount64) (**r [rd = r1 - shifted r2] *)
+ | Osublext (x: extension) (a: amount64) (**r [rd = r1 - shifted, converted r2] *)
+ | Omull (**r [rd = r1 * r2] *)
+ | Omulladd (**r [rd = r1 + r2 * r3] *)
+ | Omullsub (**r [rd = r1 - r2 * r3] *)
+ | Omullhs (**r [rd = high part of r1 * r2 (signed)] *)
+ | Omullhu (**r [rd = high part of r1 * r2 (unsigned)] *)
+ | Odivl (**r [rd = r1 / r2] (signed) *)
+ | Odivlu (**r [rd = r1 / r2] (unsigned) *)
+ | Oandl (**r [rd = r1 & r2] *)
+ | Oandlshift (s: shift) (a: amount64) (**r [rd = r1 & shifted r2] *)
+ | Oandlimm (n: int64) (**r [rd = r1 & n] *)
+ | Oorl (**r [rd = r1 | r2] *)
+ | Oorlshift (s: shift) (a: amount64) (**r [rd = r1 | shifted r2] *)
+ | Oorlimm (n: int64) (**r [rd = r1 | n] *)
+ | Oxorl (**r [rd = r1 ^ r2] *)
+ | Oxorlshift (s: shift) (a: amount64) (**r [rd = r1 ^ shifted r2] *)
+ | Oxorlimm (n: int64) (**r [rd = r1 ^ n] *)
+ | Onotl (**r [rd = ~r1] *)
+ | Onotlshift (s: shift) (a: amount64) (**r [rd = ~ shifted r1] *)
+ | Obicl (**r [rd = r1 & ~r2] *)
+ | Obiclshift (s: shift) (a: amount64) (**r [rd = r1 ^ ~ shifted r2] *)
+ | Oornl (**r [rd = r1 | ~r2] *)
+ | Oornlshift (s: shift) (a: amount64) (**r [rd = r1 | ~ shifted r2] *)
+ | Oeqvl (**r [rd = r1 ^ ~r2] *)
+ | Oeqvlshift (s: shift) (a: amount64) (**r [rd = r1 | ~ shifted r2] *)
+ | Oshll (**r [rd = r1 << r2] *)
+ | Oshrl (**r [rd = r1 >> r2] (signed) *)
+ | Oshrlu (**r [rd = r1 >> r2] (unsigned) *)
+ | Oshrlximm (n: int) (**r [rd = r1 / 2^n] (signed) *)
+ | Ozextl (s: Z) (**r [rd = zero_ext(r1,s)] *)
+ | Osextl (s: Z) (**r [rd = sign_ext(r1,s)] *)
+ | Oshllzext (s: Z) (a: amount64) (**r [rd = zero_ext(r1,s) << a] *)
+ | Oshllsext (s: Z) (a: amount64) (**r [rd = sign_ext(r1,s) << a] *)
+ | Ozextshrl (a: amount64) (s: Z) (**r [rd = zero_ext(r1 >> a, s)] *)
+ | Osextshrl (a: amount64) (s: Z) (**r [rd = sign_ext(r1 >> a, s)] *)
+(** 64-bit floating-point arithmetic *)
+ | Onegf (**r [rd = - r1] *)
+ | Oabsf (**r [rd = abs(r1)] *)
+ | Oaddf (**r [rd = r1 + r2] *)
+ | Osubf (**r [rd = r1 - r2] *)
+ | Omulf (**r [rd = r1 * r2] *)
+ | Odivf (**r [rd = r1 / r2] *)
+(** 32-bit floating-point arithmetic *)
+ | Onegfs (**r [rd = - r1] *)
+ | Oabsfs (**r [rd = abs(r1)] *)
+ | Oaddfs (**r [rd = r1 + r2] *)
+ | Osubfs (**r [rd = r1 - r2] *)
+ | Omulfs (**r [rd = r1 * r2] *)
+ | Odivfs (**r [rd = r1 / r2] *)
+ | Osingleoffloat (**r [rd] is [r1] truncated to single-precision float *)
+ | Ofloatofsingle (**r [rd] is [r1] extended to double-precision float *)
+(** Conversions between int and float *)
+ | Ointoffloat (**r [rd = signed_int_of_float64(r1)] *)
+ | Ointuoffloat (**r [rd = unsigned_int_of_float64(r1)] *)
+ | Ofloatofint (**r [rd = float64_of_signed_int(r1)] *)
+ | Ofloatofintu (**r [rd = float64_of_unsigned_int(r1)] *)
+ | Ointofsingle (**r [rd = signed_int_of_float32(r1)] *)
+ | Ointuofsingle (**r [rd = unsigned_int_of_float32(r1)] *)
+ | Osingleofint (**r [rd = float32_of_signed_int(r1)] *)
+ | Osingleofintu (**r [rd = float32_of_unsigned_int(r1)] *)
+ | Olongoffloat (**r [rd = signed_long_of_float64(r1)] *)
+ | Olonguoffloat (**r [rd = unsigned_long_of_float64(r1)] *)
+ | Ofloatoflong (**r [rd = float64_of_signed_long(r1)] *)
+ | Ofloatoflongu (**r [rd = float64_of_unsigned_long(r1)] *)
+ | Olongofsingle (**r [rd = signed_long_of_float32(r1)] *)
+ | Olonguofsingle (**r [rd = unsigned_long_of_float32(r1)] *)
+ | Osingleoflong (**r [rd = float32_of_signed_long(r1)] *)
+ | Osingleoflongu (**r [rd = float32_of_unsigned_int(r1)] *)
+(** Boolean tests *)
+ | Ocmp (cond: condition) (**r [rd = 1] if condition holds, [rd = 0] otherwise. *)
+ | Osel (cond: condition) (ty: typ). (**r [rd = rs1] if condition holds, [rd = rs2] otherwise. *)
+
+(** Addressing modes. [r1], [r2], etc, are the arguments to the addressing. *)
+
+Inductive addressing: Type :=
+ | Aindexed (ofs: int64) (**r Address is [r1 + offset] *)
+ | Aindexed2 (**r Address is [r1 + r2] *)
+ | Aindexed2shift (a: amount64) (**r Address is [r1 + r2 << a] *)
+ | Aindexed2ext (x: extension) (a: amount64) (**r Address is [r1 + sign-or-zero-ext(r2) << a] *)
+ | Aglobal (id: ident) (ofs: ptrofs) (**r Address is [global + offset] *)
+ | Ainstack (ofs: ptrofs). (**r Address is [stack_pointer + offset] *)
+
+(** Comparison functions (used in modules [CSE] and [Allocation]). *)
+
+Definition eq_amount32 (x y: amount32): {x=y} + {x<>y}.
+Proof.
+ destruct x as [x Px], y as [y Py].
+ destruct (Int.eq_dec x y).
+- subst y. assert (Px = Py) by (apply proof_irr). subst Py. left; auto.
+- right; congruence.
+Defined.
+
+Definition eq_amount64 (x y: amount64): {x=y} + {x<>y}.
+Proof.
+ destruct x as [x Px], y as [y Py].
+ destruct (Int.eq_dec x y).
+- subst y. assert (Px = Py) by (apply proof_irr). subst Py. left; auto.
+- right; congruence.
+Defined.
+
+Definition eq_shift (x y: shift): {x=y} + {x<>y}.
+Proof.
+ decide equality.
+Defined.
+
+Definition eq_extension (x y: extension): {x=y} + {x<>y}.
+Proof.
+ decide equality.
+Defined.
+
+Definition eq_condition (x y: condition) : {x=y} + {x<>y}.
+Proof.
+ assert (forall (x y: comparison), {x=y}+{x<>y}) by decide equality.
+ generalize Int.eq_dec Int64.eq_dec eq_shift eq_amount32 eq_amount64; intro.
+ decide equality.
+Defined.
+
+Definition eq_addressing (x y: addressing) : {x=y} + {x<>y}.
+Proof.
+ generalize ident_eq Int64.eq_dec Ptrofs.eq_dec eq_extension eq_amount64; intros.
+ decide equality.
+Defined.
+
+Definition eq_operation: forall (x y: operation), {x=y} + {x<>y}.
+Proof.
+ intros.
+ generalize Int.eq_dec Int64.eq_dec Ptrofs.eq_dec Float.eq_dec Float32.eq_dec
+ zeq ident_eq eq_shift eq_extension eq_amount32 eq_amount64
+ typ_eq eq_condition;
+ decide equality.
+Defined.
+
+(** Alternative:
+
+Definition beq_operation: forall (x y: operation), bool.
+Proof.
+ generalize Int.eq_dec Int64.eq_dec Ptrofs.eq_dec Float.eq_dec Float32.eq_dec
+ zeq ident_eq eq_shift eq_extension eq_amount32 eq_amount64
+ eq_condition typ_eq; boolean_equality.
+Defined.
+
+Definition eq_operation: forall (x y: operation), {x=y} + {x<>y}.
+Proof.
+ decidable_equality_from beq_operation.
+Defined.
+*)
+
+(** * Evaluation functions *)
+
+(** Evaluation of conditions, operators and addressing modes applied
+ to lists of values. Return [None] when the computation can trigger an
+ error, e.g. integer division by zero. [eval_condition] returns a boolean,
+ [eval_operation] and [eval_addressing] return a value. *)
+
+Definition eval_shift (s: shift) (v: val) (n: amount32) : val :=
+ match s with
+ | Slsl => Val.shl v (Vint n)
+ | Slsr => Val.shru v (Vint n)
+ | Sasr => Val.shr v (Vint n)
+ | Sror => Val.ror v (Vint n)
+ end.
+
+Definition eval_shiftl (s: shift) (v: val) (n: amount64) : val :=
+ match s with
+ | Slsl => Val.shll v (Vint n)
+ | Slsr => Val.shrlu v (Vint n)
+ | Sasr => Val.shrl v (Vint n)
+ | Sror => Val.rorl v (Vint n)
+ end.
+
+Definition eval_extend (x: extension) (v: val) (n: amount64) : val :=
+ Val.shll
+ (match x with
+ | Xsgn32 => Val.longofint v
+ | Xuns32 => Val.longofintu v
+ end)
+ (Vint n).
+
+Definition eval_condition (cond: condition) (vl: list val) (m: mem): option bool :=
+ match cond, vl with
+ | Ccomp c, v1 :: v2 :: nil => Val.cmp_bool c v1 v2
+ | Ccompu c, v1 :: v2 :: nil => Val.cmpu_bool (Mem.valid_pointer m) c v1 v2
+ | Ccompimm c n, v1 :: nil => Val.cmp_bool c v1 (Vint n)
+ | Ccompuimm c n, v1 :: nil => Val.cmpu_bool (Mem.valid_pointer m) c v1 (Vint n)
+ | Ccompshift c s a, v1 :: v2 :: nil => Val.cmp_bool c v1 (eval_shift s v2 a)
+ | Ccompushift c s a, v1 :: v2 :: nil => Val.cmpu_bool (Mem.valid_pointer m) c v1 (eval_shift s v2 a)
+ | Cmaskzero n, v1 :: nil => Val.cmp_bool Ceq (Val.and v1 (Vint n)) (Vint Int.zero)
+ | Cmasknotzero n, v1 :: nil => Val.cmp_bool Cne (Val.and v1 (Vint n)) (Vint Int.zero)
+
+ | Ccompl c, v1 :: v2 :: nil => Val.cmpl_bool c v1 v2
+ | Ccomplu c, v1 :: v2 :: nil => Val.cmplu_bool (Mem.valid_pointer m) c v1 v2
+ | Ccomplimm c n, v1 :: nil => Val.cmpl_bool c v1 (Vlong n)
+ | Ccompluimm c n, v1 :: nil => Val.cmplu_bool (Mem.valid_pointer m) c v1 (Vlong n)
+ | Ccomplshift c s a, v1 :: v2 :: nil => Val.cmpl_bool c v1 (eval_shiftl s v2 a)
+ | Ccomplushift c s a, v1 :: v2 :: nil => Val.cmplu_bool (Mem.valid_pointer m) c v1 (eval_shiftl s v2 a)
+ | Cmasklzero n, v1 :: nil => Val.cmpl_bool Ceq (Val.andl v1 (Vlong n)) (Vlong Int64.zero)
+ | Cmasklnotzero n, v1 :: nil => Val.cmpl_bool Cne (Val.andl v1 (Vlong n)) (Vlong Int64.zero)
+
+ | Ccompf c, v1 :: v2 :: nil => Val.cmpf_bool c v1 v2
+ | Cnotcompf c, v1 :: v2 :: nil => option_map negb (Val.cmpf_bool c v1 v2)
+ | Ccompfzero c, v1 :: nil => Val.cmpf_bool c v1 (Vfloat Float.zero)
+ | Cnotcompfzero c, v1 :: nil => option_map negb (Val.cmpf_bool c v1 (Vfloat Float.zero))
+
+ | Ccompfs c, v1 :: v2 :: nil => Val.cmpfs_bool c v1 v2
+ | Cnotcompfs c, v1 :: v2 :: nil => option_map negb (Val.cmpfs_bool c v1 v2)
+ | Ccompfszero c, v1 :: nil => Val.cmpfs_bool c v1 (Vsingle Float32.zero)
+ | Cnotcompfszero c, v1 :: nil => option_map negb (Val.cmpfs_bool c v1 (Vsingle Float32.zero))
+
+ | _, _ => None
+ end.
+
+Definition eval_operation
+ (F V: Type) (genv: Genv.t F V) (sp: val)
+ (op: operation) (vl: list val) (m: mem): option val :=
+ match op, vl with
+ | Omove, v1::nil => Some v1
+ | Ointconst n, nil => Some (Vint n)
+ | Olongconst n, nil => Some (Vlong n)
+ | Ofloatconst n, nil => Some (Vfloat n)
+ | Osingleconst n, nil => Some (Vsingle n)
+ | Oaddrsymbol s ofs, nil => Some (Genv.symbol_address genv s ofs)
+ | Oaddrstack ofs, nil => Some (Val.offset_ptr sp ofs)
+
+ | Oshift s a, v1 :: nil => Some (eval_shift s v1 a)
+ | Oadd, v1 :: v2 :: nil => Some (Val.add v1 v2)
+ | Oaddshift s a, v1 :: v2 :: nil => Some (Val.add v1 (eval_shift s v2 a))
+ | Oaddimm n, v1 :: nil => Some (Val.add v1 (Vint n))
+ | Oneg, v1 :: nil => Some (Val.neg v1)
+ | Onegshift s a, v1 :: nil => Some (Val.neg (eval_shift s v1 a))
+ | Osub, v1 :: v2 :: nil => Some (Val.sub v1 v2)
+ | Osubshift s a, v1 :: v2 :: nil => Some (Val.sub v1 (eval_shift s v2 a))
+ | Omul, v1 :: v2 :: nil => Some (Val.mul v1 v2)
+ | Omuladd, v1 :: v2 :: v3 :: nil => Some (Val.add v1 (Val.mul v2 v3))
+ | Omulsub, v1 :: v2 :: v3 :: nil => Some (Val.sub v1 (Val.mul v2 v3))
+ | Odiv, v1 :: v2 :: nil => Val.divs v1 v2
+ | Odivu, v1 :: v2 :: nil => Val.divu v1 v2
+ | Oand, v1 :: v2 :: nil => Some (Val.and v1 v2)
+ | Oandshift s a, v1 :: v2 :: nil => Some (Val.and v1 (eval_shift s v2 a))
+ | Oandimm n, v1 :: nil => Some (Val.and v1 (Vint n))
+ | Oor, v1 :: v2 :: nil => Some (Val.or v1 v2)
+ | Oorshift s a, v1 :: v2 :: nil => Some (Val.or v1 (eval_shift s v2 a))
+ | Oorimm n, v1 :: nil => Some (Val.or v1 (Vint n))
+ | Oxor, v1 :: v2 :: nil => Some (Val.xor v1 v2)
+ | Oxorshift s a, v1 :: v2 :: nil => Some (Val.xor v1 (eval_shift s v2 a))
+ | Oxorimm n, v1 :: nil => Some (Val.xor v1 (Vint n))
+ | Onot, v1 :: nil => Some (Val.notint v1)
+ | Onotshift s a, v1 :: nil => Some (Val.notint (eval_shift s v1 a))
+ | Obic, v1 :: v2 :: nil => Some (Val.and v1 (Val.notint v2))
+ | Obicshift s a, v1 :: v2 :: nil => Some (Val.and v1 (Val.notint (eval_shift s v2 a)))
+ | Oorn, v1 :: v2 :: nil => Some (Val.or v1 (Val.notint v2))
+ | Oornshift s a, v1 :: v2 :: nil => Some (Val.or v1 (Val.notint (eval_shift s v2 a)))
+ | Oeqv, v1 :: v2 :: nil => Some (Val.xor v1 (Val.notint v2))
+ | Oeqvshift s a, v1 :: v2 :: nil => Some (Val.xor v1 (Val.notint (eval_shift s v2 a)))
+ | Oshl, v1 :: v2 :: nil => Some (Val.shl v1 v2)
+ | Oshr, v1 :: v2 :: nil => Some (Val.shr v1 v2)
+ | Oshru, v1 :: v2 :: nil => Some (Val.shru v1 v2)
+ | Oshrximm n, v1::nil => Val.shrx v1 (Vint n)
+ | Ozext s, v1 :: nil => Some (Val.zero_ext s v1)
+ | Osext s, v1 :: nil => Some (Val.sign_ext s v1)
+ | Oshlzext s a, v1 :: nil => Some (Val.shl (Val.zero_ext s v1) (Vint a))
+ | Oshlsext s a, v1 :: nil => Some (Val.shl (Val.sign_ext s v1) (Vint a))
+ | Ozextshr a s, v1 :: nil => Some (Val.zero_ext s (Val.shru v1 (Vint a)))
+ | Osextshr a s, v1 :: nil => Some (Val.sign_ext s (Val.shr v1 (Vint a)))
+
+ | Oshiftl s a, v1 :: nil => Some (eval_shiftl s v1 a)
+ | Oextend x a, v1 :: nil => Some (eval_extend x v1 a)
+ | Omakelong, v1::v2::nil => Some (Val.longofwords v1 v2)
+ | Olowlong, v1::nil => Some (Val.loword v1)
+ | Ohighlong, v1::nil => Some (Val.hiword v1)
+ | Oaddl, v1 :: v2 :: nil => Some (Val.addl v1 v2)
+ | Oaddlshift s a, v1 :: v2 :: nil => Some (Val.addl v1 (eval_shiftl s v2 a))
+ | Oaddlext x a, v1 :: v2 :: nil => Some (Val.addl v1 (eval_extend x v2 a))
+ | Oaddlimm n, v1 :: nil => Some (Val.addl v1 (Vlong n))
+ | Onegl, v1 :: nil => Some (Val.negl v1)
+ | Oneglshift s a, v1 :: nil => Some (Val.negl (eval_shiftl s v1 a))
+ | Osubl, v1 :: v2 :: nil => Some (Val.subl v1 v2)
+ | Osublshift s a, v1 :: v2 :: nil => Some (Val.subl v1 (eval_shiftl s v2 a))
+ | Osublext x a, v1 :: v2 :: nil => Some (Val.subl v1 (eval_extend x v2 a))
+ | Omull, v1 :: v2 :: nil => Some (Val.mull v1 v2)
+ | Omulladd, v1 :: v2 :: v3 :: nil => Some (Val.addl v1 (Val.mull v2 v3))
+ | Omullsub, v1 :: v2 :: v3 :: nil => Some (Val.subl v1 (Val.mull v2 v3))
+ | Omullhs, v1::v2::nil => Some (Val.mullhs v1 v2)
+ | Omullhu, v1::v2::nil => Some (Val.mullhu v1 v2)
+ | Odivl, v1 :: v2 :: nil => Val.divls v1 v2
+ | Odivlu, v1 :: v2 :: nil => Val.divlu v1 v2
+ | Oandl, v1 :: v2 :: nil => Some (Val.andl v1 v2)
+ | Oandlshift s a, v1 :: v2 :: nil => Some (Val.andl v1 (eval_shiftl s v2 a))
+ | Oandlimm n, v1 :: nil => Some (Val.andl v1 (Vlong n))
+ | Oorl, v1 :: v2 :: nil => Some (Val.orl v1 v2)
+ | Oorlshift s a, v1 :: v2 :: nil => Some (Val.orl v1 (eval_shiftl s v2 a))
+ | Oorlimm n, v1 :: nil => Some (Val.orl v1 (Vlong n))
+ | Oxorl, v1 :: v2 :: nil => Some (Val.xorl v1 v2)
+ | Oxorlshift s a, v1 :: v2 :: nil => Some (Val.xorl v1 (eval_shiftl s v2 a))
+ | Oxorlimm n, v1 :: nil => Some (Val.xorl v1 (Vlong n))
+ | Onotl, v1 :: nil => Some (Val.notl v1)
+ | Onotlshift s a, v1 :: nil => Some (Val.notl (eval_shiftl s v1 a))
+ | Obicl, v1 :: v2 :: nil => Some (Val.andl v1 (Val.notl v2))
+ | Obiclshift s a, v1 :: v2 :: nil => Some (Val.andl v1 (Val.notl (eval_shiftl s v2 a)))
+ | Oornl, v1 :: v2 :: nil => Some (Val.orl v1 (Val.notl v2))
+ | Oornlshift s a, v1 :: v2 :: nil => Some (Val.orl v1 (Val.notl (eval_shiftl s v2 a)))
+ | Oeqvl, v1 :: v2 :: nil => Some (Val.xorl v1 (Val.notl v2))
+ | Oeqvlshift s a, v1 :: v2 :: nil => Some (Val.xorl v1 (Val.notl (eval_shiftl s v2 a)))
+ | Oshll, v1 :: v2 :: nil => Some (Val.shll v1 v2)
+ | Oshrl, v1 :: v2 :: nil => Some (Val.shrl v1 v2)
+ | Oshrlu, v1 :: v2 :: nil => Some (Val.shrlu v1 v2)
+ | Oshrlximm n, v1::nil => Val.shrxl v1 (Vint n)
+ | Ozextl s, v1 :: nil => Some (Val.zero_ext_l s v1)
+ | Osextl s, v1 :: nil => Some (Val.sign_ext_l s v1)
+ | Oshllzext s a, v1 :: nil => Some (Val.shll (Val.zero_ext_l s v1) (Vint a))
+ | Oshllsext s a, v1 :: nil => Some (Val.shll (Val.sign_ext_l s v1) (Vint a))
+ | Ozextshrl a s, v1 :: nil => Some (Val.zero_ext_l s (Val.shrlu v1 (Vint a)))
+ | Osextshrl a s, v1 :: nil => Some (Val.sign_ext_l s (Val.shrl v1 (Vint a)))
+
+ | Onegf, v1::nil => Some (Val.negf v1)
+ | Oabsf, v1::nil => Some (Val.absf v1)
+ | Oaddf, v1::v2::nil => Some (Val.addf v1 v2)
+ | Osubf, v1::v2::nil => Some (Val.subf v1 v2)
+ | Omulf, v1::v2::nil => Some (Val.mulf v1 v2)
+ | Odivf, v1::v2::nil => Some (Val.divf v1 v2)
+
+ | Onegfs, v1::nil => Some (Val.negfs v1)
+ | Oabsfs, v1::nil => Some (Val.absfs v1)
+ | Oaddfs, v1::v2::nil => Some (Val.addfs v1 v2)
+ | Osubfs, v1::v2::nil => Some (Val.subfs v1 v2)
+ | Omulfs, v1::v2::nil => Some (Val.mulfs v1 v2)
+ | Odivfs, v1::v2::nil => Some (Val.divfs v1 v2)
+
+ | Osingleoffloat, v1::nil => Some (Val.singleoffloat v1)
+ | Ofloatofsingle, v1::nil => Some (Val.floatofsingle v1)
+ | Ointoffloat, v1::nil => Val.intoffloat v1
+ | Ointuoffloat, v1::nil => Val.intuoffloat v1
+ | Ofloatofint, v1::nil => Val.floatofint v1
+ | Ofloatofintu, v1::nil => Val.floatofintu v1
+ | Ointofsingle, v1::nil => Val.intofsingle v1
+ | Ointuofsingle, v1::nil => Val.intuofsingle v1
+ | Osingleofint, v1::nil => Val.singleofint v1
+ | Osingleofintu, v1::nil => Val.singleofintu v1
+ | Olongoffloat, v1::nil => Val.longoffloat v1
+ | Olonguoffloat, v1::nil => Val.longuoffloat v1
+ | Ofloatoflong, v1::nil => Val.floatoflong v1
+ | Ofloatoflongu, v1::nil => Val.floatoflongu v1
+ | Olongofsingle, v1::nil => Val.longofsingle v1
+ | Olonguofsingle, v1::nil => Val.longuofsingle v1
+ | Osingleoflong, v1::nil => Val.singleoflong v1
+ | Osingleoflongu, v1::nil => Val.singleoflongu v1
+
+ | Ocmp c, _ => Some (Val.of_optbool (eval_condition c vl m))
+ | Osel c ty, v1::v2::vl => Some(Val.select (eval_condition c vl m) v1 v2 ty)
+ | _, _ => None
+ end.
+
+Definition eval_addressing
+ (F V: Type) (genv: Genv.t F V) (sp: val)
+ (addr: addressing) (vl: list val) : option val :=
+ match addr, vl with
+ | Aindexed n, v1 :: nil => Some (Val.addl v1 (Vlong n))
+ | Aindexed2, v1 :: v2 :: nil => Some (Val.addl v1 v2)
+ | Aindexed2shift a, v1 :: v2 :: nil => Some (Val.addl v1 (Val.shll v2 (Vint a)))
+ | Aindexed2ext x a, v1 :: v2 :: nil => Some (Val.addl v1 (eval_extend x v2 a))
+ | Aglobal s ofs, nil => Some (Genv.symbol_address genv s ofs)
+ | Ainstack n, nil => Some (Val.offset_ptr sp n)
+ | _, _ => None
+ end.
+
+Remark eval_addressing_Ainstack:
+ forall (F V: Type) (genv: Genv.t F V) sp ofs,
+ eval_addressing genv sp (Ainstack ofs) nil = Some (Val.offset_ptr sp ofs).
+Proof.
+ intros. reflexivity.
+Qed.
+
+Remark eval_addressing_Ainstack_inv:
+ forall (F V: Type) (genv: Genv.t F V) sp ofs vl v,
+ eval_addressing genv sp (Ainstack ofs) vl = Some v -> vl = nil /\ v = Val.offset_ptr sp ofs.
+Proof.
+ unfold eval_addressing; intros; destruct vl; inv H; auto.
+Qed.
+
+Ltac FuncInv :=
+ match goal with
+ | H: (match ?x with nil => _ | _ :: _ => _ end = Some _) |- _ =>
+ destruct x; simpl in H; FuncInv
+ | H: (match ?v with Vundef => _ | Vint _ => _ | Vfloat _ => _ | Vptr _ _ => _ end = Some _) |- _ =>
+ destruct v; simpl in H; FuncInv
+ | H: (if Archi.ptr64 then _ else _) = Some _ |- _ =>
+ change Archi.ptr64 with true in H; simpl in H; FuncInv
+ | H: (Some _ = Some _) |- _ =>
+ injection H; intros; clear H; FuncInv
+ | H: (None = Some _) |- _ =>
+ discriminate H
+ | _ =>
+ idtac
+ end.
+
+(** * Static typing of conditions, operators and addressing modes. *)
+
+Definition type_of_condition (c: condition) : list typ :=
+ match c with
+ | Ccomp _ => Tint :: Tint :: nil
+ | Ccompu _ => Tint :: Tint :: nil
+ | Ccompimm _ _ => Tint :: nil
+ | Ccompuimm _ _ => Tint :: nil
+ | Ccompshift _ _ _ => Tint :: Tint :: nil
+ | Ccompushift _ _ _ => Tint :: Tint :: nil
+ | Cmaskzero _ => Tint :: nil
+ | Cmasknotzero _ => Tint :: nil
+ | Ccompl _ => Tlong :: Tlong :: nil
+ | Ccomplu _ => Tlong :: Tlong :: nil
+ | Ccomplimm _ _ => Tlong :: nil
+ | Ccompluimm _ _ => Tlong :: nil
+ | Ccomplshift _ _ _ => Tlong :: Tlong :: nil
+ | Ccomplushift _ _ _ => Tlong :: Tlong :: nil
+ | Cmasklzero _ => Tint :: nil
+ | Cmasklnotzero _ => Tint :: nil
+ | Ccompf _ => Tfloat :: Tfloat :: nil
+ | Cnotcompf _ => Tfloat :: Tfloat :: nil
+ | Ccompfzero _ => Tfloat :: nil
+ | Cnotcompfzero _ => Tfloat :: nil
+ | Ccompfs _ => Tsingle :: Tsingle :: nil
+ | Cnotcompfs _ => Tsingle :: Tsingle :: nil
+ | Ccompfszero _ => Tsingle :: nil
+ | Cnotcompfszero _ => Tsingle :: nil
+ end.
+
+Definition type_of_operation (op: operation) : list typ * typ :=
+ match op with
+ | Omove => (nil, Tint) (* treated specially *)
+ | Ointconst _ => (nil, Tint)
+ | Olongconst _ => (nil, Tlong)
+ | Ofloatconst f => (nil, Tfloat)
+ | Osingleconst f => (nil, Tsingle)
+ | Oaddrsymbol _ _ => (nil, Tptr)
+ | Oaddrstack _ => (nil, Tptr)
+
+ | Oshift _ _ => (Tint :: nil, Tint)
+ | Oadd => (Tint :: Tint :: nil, Tint)
+ | Oaddshift _ _ => (Tint :: Tint :: nil, Tint)
+ | Oaddimm _ => (Tint :: nil, Tint)
+ | Oneg => (Tint :: nil, Tint)
+ | Onegshift _ _ => (Tint :: nil, Tint)
+ | Osub => (Tint :: Tint :: nil, Tint)
+ | Osubshift _ _ => (Tint :: Tint :: nil, Tint)
+ | Omul => (Tint :: Tint :: nil, Tint)
+ | Omuladd => (Tint :: Tint :: Tint :: nil, Tint)
+ | Omulsub => (Tint :: Tint :: Tint :: nil, Tint)
+ | Odiv => (Tint :: Tint :: nil, Tint)
+ | Odivu => (Tint :: Tint :: nil, Tint)
+ | Oand => (Tint :: Tint :: nil, Tint)
+ | Oandshift _ _ => (Tint :: Tint :: nil, Tint)
+ | Oandimm _ => (Tint :: nil, Tint)
+ | Oor => (Tint :: Tint :: nil, Tint)
+ | Oorshift _ _ => (Tint :: Tint :: nil, Tint)
+ | Oorimm _ => (Tint :: nil, Tint)
+ | Oxor => (Tint :: Tint :: nil, Tint)
+ | Oxorshift _ _ => (Tint :: Tint :: nil, Tint)
+ | Oxorimm _ => (Tint :: nil, Tint)
+ | Onot => (Tint :: nil, Tint)
+ | Onotshift _ _ => (Tint :: nil, Tint)
+ | Obic => (Tint :: Tint :: nil, Tint)
+ | Obicshift _ _ => (Tint :: Tint :: nil, Tint)
+ | Oorn => (Tint :: Tint :: nil, Tint)
+ | Oornshift _ _ => (Tint :: Tint :: nil, Tint)
+ | Oeqv => (Tint :: Tint :: nil, Tint)
+ | Oeqvshift _ _ => (Tint :: Tint :: nil, Tint)
+ | Oshl => (Tint :: Tint :: nil, Tint)
+ | Oshr => (Tint :: Tint :: nil, Tint)
+ | Oshru => (Tint :: Tint :: nil, Tint)
+ | Oshrximm _ => (Tint :: nil, Tint)
+ | Ozext _ => (Tint :: nil, Tint)
+ | Osext _ => (Tint :: nil, Tint)
+ | Oshlzext _ _ => (Tint :: nil, Tint)
+ | Oshlsext _ _ => (Tint :: nil, Tint)
+ | Ozextshr _ _ => (Tint :: nil, Tint)
+ | Osextshr _ _ => (Tint :: nil, Tint)
+
+ | Oshiftl _ _ => (Tlong :: nil, Tlong)
+ | Oextend _ _ => (Tint :: nil, Tlong)
+ | Omakelong => (Tint :: Tint :: nil, Tlong)
+ | Olowlong => (Tlong :: nil, Tint)
+ | Ohighlong => (Tlong :: nil, Tint)
+ | Oaddl => (Tlong :: Tlong :: nil, Tlong)
+ | Oaddlshift _ _ => (Tlong :: Tlong :: nil, Tlong)
+ | Oaddlext _ _ => (Tlong :: Tint :: nil, Tlong)
+ | Oaddlimm _ => (Tlong :: nil, Tlong)
+ | Onegl => (Tlong :: nil, Tlong)
+ | Oneglshift _ _ => (Tlong :: nil, Tlong)
+ | Osubl => (Tlong :: Tlong :: nil, Tlong)
+ | Osublshift _ _ => (Tlong :: Tlong :: nil, Tlong)
+ | Osublext _ _ => (Tlong :: Tint :: nil, Tlong)
+ | Omull => (Tlong :: Tlong :: nil, Tlong)
+ | Omulladd => (Tlong :: Tlong :: Tlong :: nil, Tlong)
+ | Omullsub => (Tlong :: Tlong :: Tlong :: nil, Tlong)
+ | Omullhs => (Tlong :: Tlong :: nil, Tlong)
+ | Omullhu => (Tlong :: Tlong :: nil, Tlong)
+ | Odivl => (Tlong :: Tlong :: nil, Tlong)
+ | Odivlu => (Tlong :: Tlong :: nil, Tlong)
+ | Oandl => (Tlong :: Tlong :: nil, Tlong)
+ | Oandlshift _ _ => (Tlong :: Tlong :: nil, Tlong)
+ | Oandlimm _ => (Tlong :: nil, Tlong)
+ | Oorl => (Tlong :: Tlong :: nil, Tlong)
+ | Oorlshift _ _ => (Tlong :: Tlong :: nil, Tlong)
+ | Oorlimm _ => (Tlong :: nil, Tlong)
+ | Oxorl => (Tlong :: Tlong :: nil, Tlong)
+ | Oxorlshift _ _ => (Tlong :: Tlong :: nil, Tlong)
+ | Oxorlimm _ => (Tlong :: nil, Tlong)
+ | Onotl => (Tlong :: nil, Tlong)
+ | Onotlshift _ _ => (Tlong :: nil, Tlong)
+ | Obicl => (Tlong :: Tlong :: nil, Tlong)
+ | Obiclshift _ _ => (Tlong :: Tlong :: nil, Tlong)
+ | Oornl => (Tlong :: Tlong :: nil, Tlong)
+ | Oornlshift _ _ => (Tlong :: Tlong :: nil, Tlong)
+ | Oeqvl => (Tlong :: Tlong :: nil, Tlong)
+ | Oeqvlshift _ _ => (Tlong :: Tlong :: nil, Tlong)
+ | Oshll => (Tlong :: Tint :: nil, Tlong)
+ | Oshrl => (Tlong :: Tint :: nil, Tlong)
+ | Oshrlu => (Tlong :: Tint :: nil, Tlong)
+ | Oshrlximm _ => (Tlong :: nil, Tlong)
+ | Ozextl _ => (Tlong :: nil, Tlong)
+ | Osextl _ => (Tlong :: nil, Tlong)
+ | Oshllzext _ _ => (Tlong :: nil, Tlong)
+ | Oshllsext _ _ => (Tlong :: nil, Tlong)
+ | Ozextshrl _ _ => (Tlong :: nil, Tlong)
+ | Osextshrl _ _ => (Tlong :: nil, Tlong)
+
+ | Onegf => (Tfloat :: nil, Tfloat)
+ | Oabsf => (Tfloat :: nil, Tfloat)
+ | Oaddf => (Tfloat :: Tfloat :: nil, Tfloat)
+ | Osubf => (Tfloat :: Tfloat :: nil, Tfloat)
+ | Omulf => (Tfloat :: Tfloat :: nil, Tfloat)
+ | Odivf => (Tfloat :: Tfloat :: nil, Tfloat)
+
+ | Onegfs => (Tsingle :: nil, Tsingle)
+ | Oabsfs => (Tsingle :: nil, Tsingle)
+ | Oaddfs => (Tsingle :: Tsingle :: nil, Tsingle)
+ | Osubfs => (Tsingle :: Tsingle :: nil, Tsingle)
+ | Omulfs => (Tsingle :: Tsingle :: nil, Tsingle)
+ | Odivfs => (Tsingle :: Tsingle :: nil, Tsingle)
+ | Osingleoffloat => (Tfloat :: nil, Tsingle)
+ | Ofloatofsingle => (Tsingle :: nil, Tfloat)
+
+ | Ointoffloat => (Tfloat :: nil, Tint)
+ | Ointuoffloat => (Tfloat :: nil, Tint)
+ | Ofloatofint => (Tint :: nil, Tfloat)
+ | Ofloatofintu => (Tint :: nil, Tfloat)
+ | Ointofsingle => (Tsingle :: nil, Tint)
+ | Ointuofsingle => (Tsingle :: nil, Tint)
+ | Osingleofint => (Tint :: nil, Tsingle)
+ | Osingleofintu => (Tint :: nil, Tsingle)
+ | Olongoffloat => (Tfloat :: nil, Tlong)
+ | Olonguoffloat => (Tfloat :: nil, Tlong)
+ | Ofloatoflong => (Tlong :: nil, Tfloat)
+ | Ofloatoflongu => (Tlong :: nil, Tfloat)
+ | Olongofsingle => (Tsingle :: nil, Tlong)
+ | Olonguofsingle => (Tsingle :: nil, Tlong)
+ | Osingleoflong => (Tlong :: nil, Tsingle)
+ | Osingleoflongu => (Tlong :: nil, Tsingle)
+
+ | Ocmp c => (type_of_condition c, Tint)
+ | Osel c ty => (ty :: ty :: type_of_condition c, ty)
+ end.
+
+Definition type_of_addressing (addr: addressing) : list typ :=
+ match addr with
+ | Aindexed _ => Tptr :: nil
+ | Aindexed2 => Tptr :: Tlong :: nil
+ | Aindexed2shift _ => Tptr :: Tlong :: nil
+ | Aindexed2ext _ _ => Tptr :: Tint :: nil
+ | Aglobal _ _ => nil
+ | Ainstack _ => nil
+ end.
+
+(** Weak type soundness results for [eval_operation]:
+ the result values, when defined, are always of the type predicted
+ by [type_of_operation]. *)
+
+Section SOUNDNESS.
+
+Variable A V: Type.
+Variable genv: Genv.t A V.
+
+Remark type_add:
+ forall v1 v2, Val.has_type (Val.add v1 v2) Tint.
+Proof.
+ intros. unfold Val.has_type, Val.add. destruct v1, v2; simpl; auto.
+Qed.
+
+Remark type_sub:
+ forall v1 v2, Val.has_type (Val.sub v1 v2) Tint.
+Proof.
+ intros. unfold Val.has_type, Val.add. destruct v1, v2; simpl; auto.
+Qed.
+
+Remark type_addl:
+ forall v1 v2, Val.has_type (Val.addl v1 v2) Tlong.
+Proof.
+ intros. unfold Val.has_type, Val.addl. destruct v1, v2; simpl; auto.
+Qed.
+
+Remark type_subl:
+ forall v1 v2, Val.has_type (Val.subl v1 v2) Tlong.
+Proof.
+ intros. unfold Val.has_type, Val.addl. destruct v1, v2; simpl; auto.
+ destruct (eq_block b b0); auto.
+Qed.
+
+Lemma type_of_operation_sound:
+ forall op vl sp v m,
+ op <> Omove ->
+ eval_operation genv sp op vl m = Some v ->
+ Val.has_type v (snd (type_of_operation op)).
+Proof with (try exact I; try reflexivity; auto using Val.Vptr_has_type).
+ intros.
+ destruct op; simpl; simpl in H0; FuncInv; subst; simpl.
+ (* move *)
+ - congruence.
+ (* intconst, longconst, floatconst, singleconst *)
+ - exact I.
+ - exact I.
+ - exact I.
+ - exact I.
+ (* addrsymbol *)
+ - unfold Genv.symbol_address. destruct (Genv.find_symbol genv id)...
+ (* addrstack *)
+ - destruct sp...
+ (* 32-bit integer operations *)
+ - destruct s, v0; try exact I; simpl; rewrite a32_range...
+ - apply type_add.
+ - apply type_add.
+ - apply type_add.
+ - destruct v0...
+ - destruct (eval_shift s v0 a)...
+ - apply type_sub.
+ - apply type_sub.
+ - destruct v0... destruct v1...
+ - apply type_add.
+ - apply type_sub.
+ - destruct v0; destruct v1; simpl in *; inv H0.
+ destruct (Int.eq i0 Int.zero || Int.eq i (Int.repr Int.min_signed) && Int.eq i0 Int.mone); inv H2...
+ - destruct v0; destruct v1; simpl in *; inv H0.
+ destruct (Int.eq i0 Int.zero); inv H2...
+ - destruct v0... destruct v1...
+ - destruct v0... destruct (eval_shift s v1 a)...
+ - destruct v0...
+ - destruct v0... destruct v1...
+ - destruct v0... destruct (eval_shift s v1 a)...
+ - destruct v0...
+ - destruct v0... destruct v1...
+ - destruct v0... destruct (eval_shift s v1 a)...
+ - destruct v0...
+ - destruct v0...
+ - destruct (eval_shift s v0 a)...
+ - destruct v0... destruct v1...
+ - destruct v0... destruct (eval_shift s v1 a)...
+ - destruct v0... destruct v1...
+ - destruct v0... destruct (eval_shift s v1 a)...
+ - destruct v0... destruct v1...
+ - destruct v0... destruct (eval_shift s v1 a)...
+ - destruct v0; destruct v1; simpl... destruct (Int.ltu i0 Int.iwordsize)...
+ - destruct v0; destruct v1; simpl... destruct (Int.ltu i0 Int.iwordsize)...
+ - destruct v0; destruct v1; simpl... destruct (Int.ltu i0 Int.iwordsize)...
+ - destruct v0; simpl in H0; try discriminate. destruct (Int.ltu n (Int.repr 31)); inv H0...
+ - destruct v0...
+ - destruct v0...
+ - destruct (Val.zero_ext s v0)... simpl; rewrite a32_range...
+ - destruct (Val.sign_ext s v0)... simpl; rewrite a32_range...
+ - destruct (Val.shru v0 (Vint a))...
+ - destruct (Val.shr v0 (Vint a))...
+ (* 64-bit integer operations *)
+ - destruct s, v0; try exact I; simpl; rewrite a64_range...
+ - unfold eval_extend. destruct (match x with
+ | Xsgn32 => Val.longofint v0
+ | Xuns32 => Val.longofintu v0
+ end)...
+ simpl; rewrite a64_range...
+ - destruct v0... destruct v1...
+ - destruct v0...
+ - destruct v0...
+ - apply type_addl.
+ - apply type_addl.
+ - apply type_addl.
+ - apply type_addl.
+ - destruct v0...
+ - destruct (eval_shiftl s v0 a)...
+ - apply type_subl.
+ - apply type_subl.
+ - apply type_subl.
+ - destruct v0... destruct v1...
+ - apply type_addl.
+ - apply type_subl.
+ - destruct v0... destruct v1...
+ - destruct v0... destruct v1...
+ - destruct v0; destruct v1; simpl in *; inv H0.
+ destruct (Int64.eq i0 Int64.zero || Int64.eq i (Int64.repr Int64.min_signed) && Int64.eq i0 Int64.mone); inv H2...
+ - destruct v0; destruct v1; simpl in *; inv H0.
+ destruct (Int64.eq i0 Int64.zero); inv H2...
+ - destruct v0... destruct v1...
+ - destruct v0... destruct (eval_shiftl s v1 a)...
+ - destruct v0...
+ - destruct v0... destruct v1...
+ - destruct v0... destruct (eval_shiftl s v1 a)...
+ - destruct v0...
+ - destruct v0... destruct v1...
+ - destruct v0... destruct (eval_shiftl s v1 a)...
+ - destruct v0...
+ - destruct v0...
+ - destruct (eval_shiftl s v0 a)...
+ - destruct v0... destruct v1...
+ - destruct v0... destruct (eval_shiftl s v1 a)...
+ - destruct v0... destruct v1...
+ - destruct v0... destruct (eval_shiftl s v1 a)...
+ - destruct v0... destruct v1...
+ - destruct v0... destruct (eval_shiftl s v1 a)...
+ - destruct v0; destruct v1; simpl... destruct (Int.ltu i0 Int64.iwordsize')...
+ - destruct v0; destruct v1; simpl... destruct (Int.ltu i0 Int64.iwordsize')...
+ - destruct v0; destruct v1; simpl... destruct (Int.ltu i0 Int64.iwordsize')...
+ - destruct v0; simpl in H0; try discriminate. destruct (Int.ltu n (Int.repr 63)); inv H0...
+ - destruct v0...
+ - destruct v0...
+ - destruct (Val.zero_ext_l s v0)... simpl; rewrite a64_range...
+ - destruct (Val.sign_ext_l s v0)... simpl; rewrite a64_range...
+ - destruct (Val.shrlu v0 (Vint a))...
+ - destruct (Val.shrl v0 (Vint a))...
+
+ (* 64-bit FP *)
+ - destruct v0...
+ - destruct v0...
+ - destruct v0; destruct v1...
+ - destruct v0; destruct v1...
+ - destruct v0; destruct v1...
+ - destruct v0; destruct v1...
+ (* 32-bit FP *)
+ - destruct v0...
+ - destruct v0...
+ - destruct v0; destruct v1...
+ - destruct v0; destruct v1...
+ - destruct v0; destruct v1...
+ - destruct v0; destruct v1...
+ (* singleoffloat, floatofsingle *)
+ - destruct v0...
+ - destruct v0...
+ (* intoffloat, intuoffloat *)
+ - destruct v0; simpl in H0; inv H0. destruct (Float.to_int f); inv H2...
+ - destruct v0; simpl in H0; inv H0. destruct (Float.to_intu f); inv H2...
+ (* floatofint, floatofintu *)
+ - destruct v0; simpl in H0; inv H0...
+ - destruct v0; simpl in H0; inv H0...
+ (* intofsingle, intuofsingle *)
+ - destruct v0; simpl in H0; inv H0. destruct (Float32.to_int f); inv H2...
+ - destruct v0; simpl in H0; inv H0. destruct (Float32.to_intu f); inv H2...
+ (* singleofint, singleofintu *)
+ - destruct v0; simpl in H0; inv H0...
+ - destruct v0; simpl in H0; inv H0...
+ (* longoffloat, longuoffloat *)
+ - destruct v0; simpl in H0; inv H0. destruct (Float.to_long f); inv H2...
+ - destruct v0; simpl in H0; inv H0. destruct (Float.to_longu f); inv H2...
+ (* floatoflong, floatoflongu *)
+ - destruct v0; simpl in H0; inv H0...
+ - destruct v0; simpl in H0; inv H0...
+ (* longofsingle, longuofsingle *)
+ - destruct v0; simpl in H0; inv H0. destruct (Float32.to_long f); inv H2...
+ - destruct v0; simpl in H0; inv H0. destruct (Float32.to_longu f); inv H2...
+ (* singleoflong, singleoflongu *)
+ - destruct v0; simpl in H0; inv H0...
+ - destruct v0; simpl in H0; inv H0...
+ (* cmp *)
+ - destruct (eval_condition cond vl m) as [[]|]...
+ - unfold Val.select. destruct (eval_condition cond vl m). apply Val.normalize_type. exact I.
+Qed.
+
+End SOUNDNESS.
+
+(** * Manipulating and transforming operations *)
+
+(** Constructing shift amounts *)
+
+Section SHIFT_AMOUNT.
+
+Variable l: Z.
+Hypothesis l_range: 0 <= l < 32.
+Variable N: int.
+Hypothesis N_eq: Int.unsigned N = two_p l.
+
+Remark mk_amount_range:
+ forall n, Int.ltu (Int.zero_ext l n) N = true.
+Proof.
+ intros; unfold Int.ltu. apply zlt_true. rewrite N_eq. apply (Int.zero_ext_range l n). assumption.
+Qed.
+
+Remark mk_amount_eq:
+ forall n, Int.ltu n N = true -> Int.zero_ext l n = n.
+Proof.
+ intros.
+ transitivity (Int.repr (Int.unsigned (Int.zero_ext l n))).
+ symmetry; apply Int.repr_unsigned.
+ transitivity (Int.repr (Int.unsigned n)).
+ f_equal. rewrite Int.zero_ext_mod. apply Int.ltu_inv in H. rewrite N_eq in H.
+ apply Z.mod_small. assumption. assumption.
+ apply Int.repr_unsigned.
+Qed.
+
+End SHIFT_AMOUNT.
+
+Program Definition mk_amount32 (n: int): amount32 :=
+ {| a32_amount := Int.zero_ext 5 n |}.
+Next Obligation.
+ apply mk_amount_range. omega. reflexivity.
+Qed.
+
+Lemma mk_amount32_eq: forall n,
+ Int.ltu n Int.iwordsize = true -> a32_amount (mk_amount32 n) = n.
+Proof.
+ intros. eapply mk_amount_eq; eauto. omega. reflexivity.
+Qed.
+
+Program Definition mk_amount64 (n: int): amount64 :=
+ {| a64_amount := Int.zero_ext 6 n |}.
+Next Obligation.
+ apply mk_amount_range. omega. reflexivity.
+Qed.
+
+Lemma mk_amount64_eq: forall n,
+ Int.ltu n Int64.iwordsize' = true -> a64_amount (mk_amount64 n) = n.
+Proof.
+ intros. eapply mk_amount_eq; eauto. omega. reflexivity.
+Qed.
+
+(** Recognition of move operations. *)
+
+Definition is_move_operation
+ (A: Type) (op: operation) (args: list A) : option A :=
+ match op, args with
+ | Omove, arg :: nil => Some arg
+ | _, _ => None
+ end.
+
+Lemma is_move_operation_correct:
+ forall (A: Type) (op: operation) (args: list A) (a: A),
+ is_move_operation op args = Some a ->
+ op = Omove /\ args = a :: nil.
+Proof.
+ intros until a. unfold is_move_operation; destruct op;
+ try (intros; discriminate).
+ destruct args. intros; discriminate.
+ destruct args. intros. intuition congruence.
+ intros; discriminate.
+Qed.
+
+(** [negate_condition cond] returns a condition that is logically
+ equivalent to the negation of [cond]. *)
+
+Definition negate_condition (cond: condition): condition :=
+ match cond with
+ | Ccomp c => Ccomp (negate_comparison c)
+ | Ccompu c => Ccompu (negate_comparison c)
+ | Ccompimm c n => Ccompimm (negate_comparison c) n
+ | Ccompuimm c n => Ccompuimm (negate_comparison c) n
+ | Ccompshift c s a => Ccompshift (negate_comparison c) s a
+ | Ccompushift c s a => Ccompushift (negate_comparison c) s a
+ | Cmaskzero n => Cmasknotzero n
+ | Cmasknotzero n => Cmaskzero n
+ | Ccompl c => Ccompl (negate_comparison c)
+ | Ccomplu c => Ccomplu (negate_comparison c)
+ | Ccomplimm c n => Ccomplimm (negate_comparison c) n
+ | Ccompluimm c n => Ccompluimm (negate_comparison c) n
+ | Ccomplshift c s a => Ccomplshift (negate_comparison c) s a
+ | Ccomplushift c s a => Ccomplushift (negate_comparison c) s a
+ | Cmasklzero n => Cmasklnotzero n
+ | Cmasklnotzero n => Cmasklzero n
+ | Ccompf c => Cnotcompf c
+ | Cnotcompf c => Ccompf c
+ | Ccompfzero c => Cnotcompfzero c
+ | Cnotcompfzero c => Ccompfzero c
+ | Ccompfs c => Cnotcompfs c
+ | Cnotcompfs c => Ccompfs c
+ | Ccompfszero c => Cnotcompfszero c
+ | Cnotcompfszero c => Ccompfszero c
+ end.
+
+Lemma eval_negate_condition:
+ forall cond vl m,
+ eval_condition (negate_condition cond) vl m = option_map negb (eval_condition cond vl m).
+Proof.
+ intros. destruct cond; simpl.
+ repeat (destruct vl; auto). apply Val.negate_cmp_bool.
+ repeat (destruct vl; auto). apply Val.negate_cmpu_bool.
+ repeat (destruct vl; auto). apply Val.negate_cmp_bool.
+ repeat (destruct vl; auto). apply Val.negate_cmpu_bool.
+ repeat (destruct vl; auto). apply Val.negate_cmp_bool.
+ repeat (destruct vl; auto). apply Val.negate_cmpu_bool.
+ repeat (destruct vl; auto). apply (Val.negate_cmp_bool Ceq).
+ repeat (destruct vl; auto). apply (Val.negate_cmp_bool Cne).
+ repeat (destruct vl; auto). apply Val.negate_cmpl_bool.
+ repeat (destruct vl; auto). apply Val.negate_cmplu_bool.
+ repeat (destruct vl; auto). apply Val.negate_cmpl_bool.
+ repeat (destruct vl; auto). apply Val.negate_cmplu_bool.
+ repeat (destruct vl; auto). apply Val.negate_cmpl_bool.
+ repeat (destruct vl; auto). apply Val.negate_cmplu_bool.
+ repeat (destruct vl; auto). apply (Val.negate_cmpl_bool Ceq).
+ repeat (destruct vl; auto). apply (Val.negate_cmpl_bool Cne).
+ repeat (destruct vl; auto).
+ repeat (destruct vl; auto). destruct (Val.cmpf_bool c v v0) as [[]|]; auto.
+ repeat (destruct vl; auto).
+ repeat (destruct vl; auto). destruct (Val.cmpf_bool c v (Vfloat Float.zero)) as [[]|]; auto.
+ repeat (destruct vl; auto).
+ repeat (destruct vl; auto). destruct (Val.cmpfs_bool c v v0) as [[]|]; auto.
+ repeat (destruct vl; auto).
+ repeat (destruct vl; auto). destruct (Val.cmpfs_bool c v (Vsingle Float32.zero)) as [[]|]; auto.
+Qed.
+
+(** Shifting stack-relative references. This is used in [Stacking]. *)
+
+Definition shift_stack_addressing (delta: Z) (addr: addressing) :=
+ match addr with
+ | Ainstack ofs => Ainstack (Ptrofs.add ofs (Ptrofs.repr delta))
+ | _ => addr
+ end.
+
+Definition shift_stack_operation (delta: Z) (op: operation) :=
+ match op with
+ | Oaddrstack ofs => Oaddrstack (Ptrofs.add ofs (Ptrofs.repr delta))
+ | _ => op
+ end.
+
+Lemma type_shift_stack_addressing:
+ forall delta addr, type_of_addressing (shift_stack_addressing delta addr) = type_of_addressing addr.
+Proof.
+ intros. destruct addr; auto.
+Qed.
+
+Lemma type_shift_stack_operation:
+ forall delta op, type_of_operation (shift_stack_operation delta op) = type_of_operation op.
+Proof.
+ intros. destruct op; auto.
+Qed.
+
+Lemma eval_shift_stack_addressing:
+ forall F V (ge: Genv.t F V) sp addr vl delta,
+ eval_addressing ge (Vptr sp Ptrofs.zero) (shift_stack_addressing delta addr) vl =
+ eval_addressing ge (Vptr sp (Ptrofs.repr delta)) addr vl.
+Proof.
+ intros. destruct addr; simpl; auto. destruct vl; auto.
+ rewrite Ptrofs.add_zero_l, Ptrofs.add_commut; auto.
+Qed.
+
+Lemma eval_shift_stack_operation:
+ forall F V (ge: Genv.t F V) sp op vl m delta,
+ eval_operation ge (Vptr sp Ptrofs.zero) (shift_stack_operation delta op) vl m =
+ eval_operation ge (Vptr sp (Ptrofs.repr delta)) op vl m.
+Proof.
+ intros. destruct op; simpl; auto. destruct vl; auto.
+ rewrite Ptrofs.add_zero_l, Ptrofs.add_commut; auto.
+Qed.
+
+(** Offset an addressing mode [addr] by a quantity [delta], so that
+ it designates the pointer [delta] bytes past the pointer designated
+ by [addr]. May be undefined, in which case [None] is returned. *)
+
+Definition offset_addressing (addr: addressing) (delta: Z) : option addressing :=
+ match addr with
+ | Aindexed n => Some(Aindexed (Int64.add n (Int64.repr delta)))
+ | Aindexed2 => None
+ | Aindexed2shift _ => None
+ | Aindexed2ext _ _ => None
+ | Aglobal id n => Some(Aglobal id (Ptrofs.add n (Ptrofs.repr delta)))
+ | Ainstack n => Some(Ainstack (Ptrofs.add n (Ptrofs.repr delta)))
+ end.
+
+Lemma eval_offset_addressing:
+ forall (F V: Type) (ge: Genv.t F V) sp addr args delta addr' v,
+ offset_addressing addr delta = Some addr' ->
+ eval_addressing ge sp addr args = Some v ->
+ Archi.ptr64 = false ->
+ eval_addressing ge sp addr' args = Some(Val.add v (Vint (Int.repr delta))).
+Proof.
+ intros. discriminate.
+Qed.
+
+(** Operations that are so cheap to recompute that CSE should not factor them out. *)
+
+Definition is_trivial_op (op: operation) : bool :=
+ match op with
+ | Omove => true
+ | Ointconst n => Int.eq (Int.sign_ext 16 n) n
+ | Olongconst n => Int64.eq (Int64.sign_ext 16 n) n
+ | Oaddrstack _ => true
+ | _ => false
+ end.
+
+(** Operations that depend on the memory state. *)
+
+Definition cond_depends_on_memory (c: condition) : bool :=
+ match c with
+ | Ccomplu _ | Ccompluimm _ _ | Ccomplushift _ _ _ => true
+ | _ => false
+ end.
+
+Lemma cond_depends_on_memory_correct:
+ forall c args m1 m2,
+ cond_depends_on_memory c = false ->
+ eval_condition c args m1 = eval_condition c args m2.
+Proof.
+ intros; destruct c; simpl; discriminate || reflexivity.
+Qed.
+
+Definition op_depends_on_memory (op: operation) : bool :=
+ match op with
+ | Ocmp c => cond_depends_on_memory c
+ | Osel c yu => cond_depends_on_memory c
+ | _ => false
+ end.
+
+Lemma op_depends_on_memory_correct:
+ forall (F V: Type) (ge: Genv.t F V) sp op args m1 m2,
+ op_depends_on_memory op = false ->
+ eval_operation ge sp op args m1 = eval_operation ge sp op args m2.
+Proof.
+ intros. destruct op; auto.
+ simpl. rewrite (cond_depends_on_memory_correct cond args m1 m2 H). auto.
+ simpl. destruct args; auto. destruct args; auto.
+ rewrite (cond_depends_on_memory_correct cond args m1 m2 H). auto.
+Qed.
+
+(** Global variables mentioned in an operation or addressing mode *)
+
+Definition globals_addressing (addr: addressing) : list ident :=
+ match addr with
+ | Aglobal s ofs => s :: nil
+ | _ => nil
+ end.
+
+Definition globals_operation (op: operation) : list ident :=
+ match op with
+ | Oaddrsymbol s ofs => s :: nil
+ | _ => nil
+ end.
+
+(** * Invariance and compatibility properties. *)
+
+(** [eval_operation] and [eval_addressing] depend on a global environment
+ for resolving references to global symbols. We show that they give
+ the same results if a global environment is replaced by another that
+ assigns the same addresses to the same symbols. *)
+
+Section GENV_TRANSF.
+
+Variable F1 F2 V1 V2: Type.
+Variable ge1: Genv.t F1 V1.
+Variable ge2: Genv.t F2 V2.
+Hypothesis agree_on_symbols:
+ forall (s: ident), Genv.find_symbol ge2 s = Genv.find_symbol ge1 s.
+
+Lemma eval_addressing_preserved:
+ forall sp addr vl,
+ eval_addressing ge2 sp addr vl = eval_addressing ge1 sp addr vl.
+Proof.
+ intros.
+ unfold eval_addressing; destruct addr; auto. destruct vl; auto.
+ unfold Genv.symbol_address. rewrite agree_on_symbols; auto.
+Qed.
+
+Lemma eval_operation_preserved:
+ forall sp op vl m,
+ eval_operation ge2 sp op vl m = eval_operation ge1 sp op vl m.
+Proof.
+ intros.
+ unfold eval_operation; destruct op; auto. destruct vl; auto.
+ unfold Genv.symbol_address. rewrite agree_on_symbols; auto.
+Qed.
+
+End GENV_TRANSF.
+
+(** Compatibility of the evaluation functions with value injections. *)
+
+Section EVAL_COMPAT.
+
+Variable F1 F2 V1 V2: Type.
+Variable ge1: Genv.t F1 V1.
+Variable ge2: Genv.t F2 V2.
+Variable f: meminj.
+
+Variable m1: mem.
+Variable m2: mem.
+
+Hypothesis valid_pointer_inj:
+ forall b1 ofs b2 delta,
+ f b1 = Some(b2, delta) ->
+ Mem.valid_pointer m1 b1 (Ptrofs.unsigned ofs) = true ->
+ Mem.valid_pointer m2 b2 (Ptrofs.unsigned (Ptrofs.add ofs (Ptrofs.repr delta))) = true.
+
+Hypothesis weak_valid_pointer_inj:
+ forall b1 ofs b2 delta,
+ f b1 = Some(b2, delta) ->
+ Mem.weak_valid_pointer m1 b1 (Ptrofs.unsigned ofs) = true ->
+ Mem.weak_valid_pointer m2 b2 (Ptrofs.unsigned (Ptrofs.add ofs (Ptrofs.repr delta))) = true.
+
+Hypothesis weak_valid_pointer_no_overflow:
+ forall b1 ofs b2 delta,
+ f b1 = Some(b2, delta) ->
+ Mem.weak_valid_pointer m1 b1 (Ptrofs.unsigned ofs) = true ->
+ 0 <= Ptrofs.unsigned ofs + Ptrofs.unsigned (Ptrofs.repr delta) <= Ptrofs.max_unsigned.
+
+Hypothesis valid_different_pointers_inj:
+ forall b1 ofs1 b2 ofs2 b1' delta1 b2' delta2,
+ b1 <> b2 ->
+ Mem.valid_pointer m1 b1 (Ptrofs.unsigned ofs1) = true ->
+ Mem.valid_pointer m1 b2 (Ptrofs.unsigned ofs2) = true ->
+ f b1 = Some (b1', delta1) ->
+ f b2 = Some (b2', delta2) ->
+ b1' <> b2' \/
+ Ptrofs.unsigned (Ptrofs.add ofs1 (Ptrofs.repr delta1)) <> Ptrofs.unsigned (Ptrofs.add ofs2 (Ptrofs.repr delta2)).
+
+Ltac InvInject :=
+ match goal with
+ | [ H: Val.inject _ (Vint _) _ |- _ ] =>
+ inv H; InvInject
+ | [ H: Val.inject _ (Vfloat _) _ |- _ ] =>
+ inv H; InvInject
+ | [ H: Val.inject _ (Vptr _ _) _ |- _ ] =>
+ inv H; InvInject
+ | [ H: Val.inject_list _ nil _ |- _ ] =>
+ inv H; InvInject
+ | [ H: Val.inject_list _ (_ :: _) _ |- _ ] =>
+ inv H; InvInject
+ | _ => idtac
+ end.
+
+Lemma eval_shift_inject:
+ forall v1 v2 s a,
+ Val.inject f v1 v2 -> Val.inject f (eval_shift s v1 a) (eval_shift s v2 a).
+Proof.
+ intros; inv H; destruct s; simpl; auto; rewrite a32_range; auto.
+Qed.
+
+Lemma eval_shiftl_inject:
+ forall v1 v2 s a,
+ Val.inject f v1 v2 -> Val.inject f (eval_shiftl s v1 a) (eval_shiftl s v2 a).
+Proof.
+ intros; inv H; destruct s; simpl; auto; rewrite a64_range; auto.
+Qed.
+
+Lemma eval_extend_inject:
+ forall v1 v2 x a,
+ Val.inject f v1 v2 -> Val.inject f (eval_extend x v1 a) (eval_extend x v2 a).
+Proof.
+ unfold eval_extend; intros; inv H; destruct x; simpl; auto; rewrite a64_range; auto.
+Qed.
+
+Lemma eval_condition_inj:
+ forall cond vl1 vl2 b,
+ Val.inject_list f vl1 vl2 ->
+ eval_condition cond vl1 m1 = Some b ->
+ eval_condition cond vl2 m2 = Some b.
+Proof.
+ intros. destruct cond; simpl in H0; FuncInv; InvInject; simpl; auto.
+(* 32-bit integers *)
+- inv H3; inv H2; simpl in H0; inv H0; auto.
+- eauto 3 using Val.cmpu_bool_inject, Mem.valid_pointer_implies.
+- inv H3; simpl in H0; inv H0; auto.
+- eauto 3 using Val.cmpu_bool_inject, Mem.valid_pointer_implies.
+- revert H0. generalize (eval_shift_inject s a H2); intros J; inv H3; inv J; simpl; congruence.
+- eauto 3 using Val.cmpu_bool_inject, Mem.valid_pointer_implies, eval_shift_inject.
+- inv H3; inv H0; auto.
+- inv H3; inv H0; auto.
+(* 64-bit integers *)
+- inv H3; inv H2; simpl in H0; inv H0; auto.
+- eauto 3 using Val.cmplu_bool_inject, Mem.valid_pointer_implies.
+- inv H3; simpl in H0; inv H0; auto.
+- eauto 3 using Val.cmplu_bool_inject, Mem.valid_pointer_implies.
+- revert H0. generalize (eval_shiftl_inject s a H2); intros J; inv H3; inv J; simpl; congruence.
+- eauto 3 using Val.cmplu_bool_inject, Mem.valid_pointer_implies, eval_shiftl_inject.
+- inv H3; inv H0; auto.
+- inv H3; inv H0; auto.
+(* 64-bit floats *)
+- inv H3; inv H2; simpl in H0; inv H0; auto.
+- inv H3; inv H2; simpl in H0; inv H0; auto.
+- inv H3; simpl in H0; inv H0; auto.
+- inv H3; simpl in H0; inv H0; auto.
+(* 32-bit floats *)
+- inv H3; inv H2; simpl in H0; inv H0; auto.
+- inv H3; inv H2; simpl in H0; inv H0; auto.
+- inv H3; simpl in H0; inv H0; auto.
+- inv H3; simpl in H0; inv H0; auto.
+Qed.
+
+Ltac TrivialExists :=
+ match goal with
+ | [ |- exists v2, Some ?v1 = Some v2 /\ Val.inject _ _ v2 ] =>
+ exists v1; split; auto
+ | _ => idtac
+ end.
+
+Lemma eval_operation_inj:
+ forall op sp1 vl1 sp2 vl2 v1,
+ (forall id ofs,
+ In id (globals_operation op) ->
+ Val.inject f (Genv.symbol_address ge1 id ofs) (Genv.symbol_address ge2 id ofs)) ->
+ Val.inject f sp1 sp2 ->
+ Val.inject_list f vl1 vl2 ->
+ eval_operation ge1 sp1 op vl1 m1 = Some v1 ->
+ exists v2, eval_operation ge2 sp2 op vl2 m2 = Some v2 /\ Val.inject f v1 v2.
+Proof.
+ intros until v1; intros GL; intros. destruct op; simpl in H1; simpl; FuncInv; InvInject; TrivialExists.
+ (* addrsymbol *)
+ - apply GL; simpl; auto.
+ (* addrstack *)
+ - apply Val.offset_ptr_inject; auto.
+ (* shift *)
+ - apply eval_shift_inject; auto.
+ (* add *)
+ - apply Val.add_inject; auto.
+ - apply Val.add_inject; auto using eval_shift_inject.
+ - apply Val.add_inject; auto.
+ (* neg, sub *)
+ - inv H4; simpl; auto.
+ - generalize (eval_shift_inject s a H4); intros J; inv J; simpl; auto.
+ - apply Val.sub_inject; auto.
+ - apply Val.sub_inject; auto using eval_shift_inject.
+ (* mul, muladd, mulsub *)
+ - inv H4; inv H2; simpl; auto.
+ - apply Val.add_inject; auto. inv H2; inv H3; simpl; auto.
+ - apply Val.sub_inject; auto. inv H2; inv H3; simpl; auto.
+ (* div, divu *)
+ - inv H4; inv H3; simpl in H1; inv H1. simpl.
+ destruct (Int.eq i0 Int.zero
+ || Int.eq i (Int.repr Int.min_signed) && Int.eq i0 Int.mone); inv H2.
+ TrivialExists.
+ - inv H4; inv H3; simpl in H1; inv H1. simpl.
+ destruct (Int.eq i0 Int.zero); inv H2. TrivialExists.
+ (* and*)
+ - inv H4; inv H2; simpl; auto.
+ - generalize (eval_shift_inject s a H2); intros J; inv H4; inv J; simpl; auto.
+ - inv H4; simpl; auto.
+ (* or *)
+ - inv H4; inv H2; simpl; auto.
+ - generalize (eval_shift_inject s a H2); intros J; inv H4; inv J; simpl; auto.
+ - inv H4; simpl; auto.
+ (* xor *)
+ - inv H4; inv H2; simpl; auto.
+ - generalize (eval_shift_inject s a H2); intros J; inv H4; inv J; simpl; auto.
+ - inv H4; simpl; auto.
+ (* not *)
+ - inv H4; simpl; auto.
+ - generalize (eval_shift_inject s a H4); intros J; inv J; simpl; auto.
+ (* bic *)
+ - inv H4; inv H2; simpl; auto.
+ - generalize (eval_shift_inject s a H2); intros J; inv H4; inv J; simpl; auto.
+ (* nor *)
+ - inv H4; inv H2; simpl; auto.
+ - generalize (eval_shift_inject s a H2); intros J; inv H4; inv J; simpl; auto.
+ (* eqv *)
+ - inv H4; inv H2; simpl; auto.
+ - generalize (eval_shift_inject s a H2); intros J; inv H4; inv J; simpl; auto.
+ (* shl *)
+ - inv H4; inv H2; simpl; auto. destruct (Int.ltu i0 Int.iwordsize); auto.
+ (* shr *)
+ - inv H4; inv H2; simpl; auto. destruct (Int.ltu i0 Int.iwordsize); auto.
+ (* shru *)
+ - inv H4; inv H2; simpl; auto. destruct (Int.ltu i0 Int.iwordsize); auto.
+ (* shrx *)
+ - inv H4; simpl in H1; try discriminate. simpl.
+ destruct (Int.ltu n (Int.repr 31)); inv H1. TrivialExists.
+ (* shift-ext *)
+ - inv H4; simpl; auto.
+ - inv H4; simpl; auto.
+ - inv H4; simpl; auto; rewrite a32_range; auto.
+ - inv H4; simpl; auto; rewrite a32_range; auto.
+ - inv H4; simpl; auto; rewrite a32_range; simpl; auto.
+ - inv H4; simpl; auto; rewrite a32_range; simpl; auto.
+
+ (* shiftl *)
+ - apply eval_shiftl_inject; auto.
+ (* extend *)
+ - apply eval_extend_inject; auto.
+ (* makelong, low, high *)
+ - inv H4; inv H2; simpl; auto.
+ - inv H4; simpl; auto.
+ - inv H4; simpl; auto.
+ (* addl *)
+ - apply Val.addl_inject; auto.
+ - apply Val.addl_inject; auto using eval_shiftl_inject.
+ - apply Val.addl_inject; auto using eval_extend_inject.
+ - apply Val.addl_inject; auto.
+ (* negl, subl *)
+ - inv H4; simpl; auto.
+ - generalize (eval_shiftl_inject s a H4); intros J; inv J; simpl; auto.
+ - apply Val.subl_inject; auto.
+ - apply Val.subl_inject; auto using eval_shiftl_inject.
+ - apply Val.subl_inject; auto using eval_extend_inject.
+ (* mull, mulladd, mullsub, mullhs, mullhu *)
+ - inv H4; inv H2; simpl; auto.
+ - apply Val.addl_inject; auto. inv H2; inv H3; simpl; auto.
+ - apply Val.subl_inject; auto. inv H2; inv H3; simpl; auto.
+ - inv H4; inv H2; simpl; auto.
+ - inv H4; inv H2; simpl; auto.
+ (* divl, divlu *)
+ - inv H4; inv H3; simpl in H1; inv H1. simpl.
+ destruct (Int64.eq i0 Int64.zero
+ || Int64.eq i (Int64.repr Int64.min_signed) && Int64.eq i0 Int64.mone); inv H2.
+ TrivialExists.
+ - inv H4; inv H3; simpl in H1; inv H1. simpl.
+ destruct (Int64.eq i0 Int64.zero); inv H2. TrivialExists.
+ (* andl *)
+ - inv H4; inv H2; simpl; auto.
+ - generalize (eval_shiftl_inject s a H2); intros J; inv H4; inv J; simpl; auto.
+ - inv H4; simpl; auto.
+ (* orl *)
+ - inv H4; inv H2; simpl; auto.
+ - generalize (eval_shiftl_inject s a H2); intros J; inv H4; inv J; simpl; auto.
+ - inv H4; simpl; auto.
+ (* xorl *)
+ - inv H4; inv H2; simpl; auto.
+ - generalize (eval_shiftl_inject s a H2); intros J; inv H4; inv J; simpl; auto.
+ - inv H4; simpl; auto.
+ (* notl *)
+ - inv H4; simpl; auto.
+ - generalize (eval_shiftl_inject s a H4); intros J; inv J; simpl; auto.
+ (* bicl *)
+ - inv H4; inv H2; simpl; auto.
+ - generalize (eval_shiftl_inject s a H2); intros J; inv H4; inv J; simpl; auto.
+ (* norl *)
+ - inv H4; inv H2; simpl; auto.
+ - generalize (eval_shiftl_inject s a H2); intros J; inv H4; inv J; simpl; auto.
+ (* eqvl *)
+ - inv H4; inv H2; simpl; auto.
+ - generalize (eval_shiftl_inject s a H2); intros J; inv H4; inv J; simpl; auto.
+ (* shll *)
+ - inv H4; inv H2; simpl; auto. destruct (Int.ltu i0 Int64.iwordsize'); auto.
+ (* shrl *)
+ - inv H4; inv H2; simpl; auto. destruct (Int.ltu i0 Int64.iwordsize'); auto.
+ (* shrlu *)
+ - inv H4; inv H2; simpl; auto. destruct (Int.ltu i0 Int64.iwordsize'); auto.
+ (* shrlx *)
+ - inv H4; simpl in H1; try discriminate. simpl.
+ destruct (Int.ltu n (Int.repr 63)); inv H1. TrivialExists.
+ (* shift-ext *)
+ - inv H4; simpl; auto.
+ - inv H4; simpl; auto.
+ - inv H4; simpl; auto; rewrite a64_range; auto.
+ - inv H4; simpl; auto; rewrite a64_range; auto.
+ - inv H4; simpl; auto; rewrite a64_range; simpl; auto.
+ - inv H4; simpl; auto; rewrite a64_range; simpl; auto.
+
+ (* negf, absf *)
+ - inv H4; simpl; auto.
+ - inv H4; simpl; auto.
+ (* addf, subf *)
+ - inv H4; inv H2; simpl; auto.
+ - inv H4; inv H2; simpl; auto.
+ (* mulf, divf *)
+ - inv H4; inv H2; simpl; auto.
+ - inv H4; inv H2; simpl; auto.
+ (* negfs, absfs *)
+ - inv H4; simpl; auto.
+ - inv H4; simpl; auto.
+ (* addfs, subfs *)
+ - inv H4; inv H2; simpl; auto.
+ - inv H4; inv H2; simpl; auto.
+ (* mulfs, divfs *)
+ - inv H4; inv H2; simpl; auto.
+ - inv H4; inv H2; simpl; auto.
+ (* singleoffloat, floatofsingle *)
+ - inv H4; simpl; auto.
+ - inv H4; simpl; auto.
+ (* intoffloat, intuoffloat *)
+ - inv H4; simpl in H1; inv H1. simpl. destruct (Float.to_int f0); simpl in H2; inv H2.
+ exists (Vint i); auto.
+ - inv H4; simpl in H1; inv H1. simpl. destruct (Float.to_intu f0); simpl in H2; inv H2.
+ exists (Vint i); auto.
+ (* floatofint, floatofintu *)
+ - inv H4; simpl in H1; inv H1. simpl. TrivialExists.
+ - inv H4; simpl in H1; inv H1. simpl. TrivialExists.
+ (* intofsingle, intuofsingle *)
+ - inv H4; simpl in H1; inv H1. simpl. destruct (Float32.to_int f0); simpl in H2; inv H2.
+ exists (Vint i); auto.
+ - inv H4; simpl in H1; inv H1. simpl. destruct (Float32.to_intu f0); simpl in H2; inv H2.
+ exists (Vint i); auto.
+ (* singleofint, singleofintu *)
+ - inv H4; simpl in H1; inv H1. simpl. TrivialExists.
+ - inv H4; simpl in H1; inv H1. simpl. TrivialExists.
+ (* longoffloat, longuoffloat *)
+ - inv H4; simpl in H1; inv H1. simpl. destruct (Float.to_long f0); simpl in H2; inv H2.
+ exists (Vlong i); auto.
+ - inv H4; simpl in H1; inv H1. simpl. destruct (Float.to_longu f0); simpl in H2; inv H2.
+ exists (Vlong i); auto.
+ (* floatoflong, floatoflongu *)
+ - inv H4; simpl in H1; inv H1. simpl. TrivialExists.
+ - inv H4; simpl in H1; inv H1. simpl. TrivialExists.
+ (* longofsingle, longuofsingle *)
+ - inv H4; simpl in H1; inv H1. simpl. destruct (Float32.to_long f0); simpl in H2; inv H2.
+ exists (Vlong i); auto.
+ - inv H4; simpl in H1; inv H1. simpl. destruct (Float32.to_longu f0); simpl in H2; inv H2.
+ exists (Vlong i); auto.
+ (* singleoflong, singleoflongu *)
+ - inv H4; simpl in H1; inv H1. simpl. TrivialExists.
+ - inv H4; simpl in H1; inv H1. simpl. TrivialExists.
+ (* cmp, sel *)
+ - subst v1. destruct (eval_condition cond vl1 m1) eqn:?.
+ exploit eval_condition_inj; eauto. intros EQ; rewrite EQ.
+ destruct b; simpl; constructor.
+ simpl; constructor.
+ - apply Val.select_inject; auto.
+ destruct (eval_condition cond vl1 m1) eqn:?; auto.
+ right; symmetry; eapply eval_condition_inj; eauto.
+Qed.
+
+Lemma eval_addressing_inj:
+ forall addr sp1 vl1 sp2 vl2 v1,
+ (forall id ofs,
+ In id (globals_addressing addr) ->
+ Val.inject f (Genv.symbol_address ge1 id ofs) (Genv.symbol_address ge2 id ofs)) ->
+ Val.inject f sp1 sp2 ->
+ Val.inject_list f vl1 vl2 ->
+ eval_addressing ge1 sp1 addr vl1 = Some v1 ->
+ exists v2, eval_addressing ge2 sp2 addr vl2 = Some v2 /\ Val.inject f v1 v2.
+Proof.
+ intros. destruct addr; simpl in H2; simpl; FuncInv; InvInject; TrivialExists.
+- apply Val.addl_inject; auto.
+- apply Val.addl_inject; auto.
+- apply Val.addl_inject; auto. inv H3; simpl; auto; rewrite a64_range; auto.
+- apply Val.addl_inject; auto using eval_extend_inject.
+- apply H; simpl; auto.
+- apply Val.offset_ptr_inject; auto.
+Qed.
+
+End EVAL_COMPAT.
+
+(** Compatibility of the evaluation functions with the ``is less defined'' relation over values. *)
+
+Section EVAL_LESSDEF.
+
+Variable F V: Type.
+Variable genv: Genv.t F V.
+
+Remark valid_pointer_extends:
+ forall m1 m2, Mem.extends m1 m2 ->
+ forall b1 ofs b2 delta,
+ Some(b1, 0) = Some(b2, delta) ->
+ Mem.valid_pointer m1 b1 (Ptrofs.unsigned ofs) = true ->
+ Mem.valid_pointer m2 b2 (Ptrofs.unsigned (Ptrofs.add ofs (Ptrofs.repr delta))) = true.
+Proof.
+ intros. inv H0. rewrite Ptrofs.add_zero. eapply Mem.valid_pointer_extends; eauto.
+Qed.
+
+Remark weak_valid_pointer_extends:
+ forall m1 m2, Mem.extends m1 m2 ->
+ forall b1 ofs b2 delta,
+ Some(b1, 0) = Some(b2, delta) ->
+ Mem.weak_valid_pointer m1 b1 (Ptrofs.unsigned ofs) = true ->
+ Mem.weak_valid_pointer m2 b2 (Ptrofs.unsigned (Ptrofs.add ofs (Ptrofs.repr delta))) = true.
+Proof.
+ intros. inv H0. rewrite Ptrofs.add_zero. eapply Mem.weak_valid_pointer_extends; eauto.
+Qed.
+
+Remark weak_valid_pointer_no_overflow_extends:
+ forall m1 b1 ofs b2 delta,
+ Some(b1, 0) = Some(b2, delta) ->
+ Mem.weak_valid_pointer m1 b1 (Ptrofs.unsigned ofs) = true ->
+ 0 <= Ptrofs.unsigned ofs + Ptrofs.unsigned (Ptrofs.repr delta) <= Ptrofs.max_unsigned.
+Proof.
+ intros. inv H. rewrite Z.add_0_r. apply Ptrofs.unsigned_range_2.
+Qed.
+
+Remark valid_different_pointers_extends:
+ forall m1 b1 ofs1 b2 ofs2 b1' delta1 b2' delta2,
+ b1 <> b2 ->
+ Mem.valid_pointer m1 b1 (Ptrofs.unsigned ofs1) = true ->
+ Mem.valid_pointer m1 b2 (Ptrofs.unsigned ofs2) = true ->
+ Some(b1, 0) = Some (b1', delta1) ->
+ Some(b2, 0) = Some (b2', delta2) ->
+ b1' <> b2' \/
+ Ptrofs.unsigned(Ptrofs.add ofs1 (Ptrofs.repr delta1)) <> Ptrofs.unsigned(Ptrofs.add ofs2 (Ptrofs.repr delta2)).
+Proof.
+ intros. inv H2; inv H3. auto.
+Qed.
+
+Lemma eval_condition_lessdef:
+ forall cond vl1 vl2 b m1 m2,
+ Val.lessdef_list vl1 vl2 ->
+ Mem.extends m1 m2 ->
+ eval_condition cond vl1 m1 = Some b ->
+ eval_condition cond vl2 m2 = Some b.
+Proof.
+ intros. eapply eval_condition_inj with (f := fun b => Some(b, 0)) (m1 := m1).
+ apply valid_pointer_extends; auto.
+ apply weak_valid_pointer_extends; auto.
+ apply weak_valid_pointer_no_overflow_extends.
+ apply valid_different_pointers_extends; auto.
+ rewrite <- val_inject_list_lessdef. eauto. auto.
+Qed.
+
+Lemma eval_operation_lessdef:
+ forall sp op vl1 vl2 v1 m1 m2,
+ Val.lessdef_list vl1 vl2 ->
+ Mem.extends m1 m2 ->
+ eval_operation genv sp op vl1 m1 = Some v1 ->
+ exists v2, eval_operation genv sp op vl2 m2 = Some v2 /\ Val.lessdef v1 v2.
+Proof.
+ intros. rewrite val_inject_list_lessdef in H.
+ assert (exists v2 : val,
+ eval_operation genv sp op vl2 m2 = Some v2
+ /\ Val.inject (fun b => Some(b, 0)) v1 v2).
+ eapply eval_operation_inj with (m1 := m1) (sp1 := sp).
+ apply valid_pointer_extends; auto.
+ apply weak_valid_pointer_extends; auto.
+ apply weak_valid_pointer_no_overflow_extends.
+ apply valid_different_pointers_extends; auto.
+ intros. apply val_inject_lessdef. auto.
+ apply val_inject_lessdef; auto.
+ eauto.
+ auto.
+ destruct H2 as [v2 [A B]]. exists v2; split; auto. rewrite val_inject_lessdef; auto.
+Qed.
+
+Lemma eval_addressing_lessdef:
+ forall sp addr vl1 vl2 v1,
+ Val.lessdef_list vl1 vl2 ->
+ eval_addressing genv sp addr vl1 = Some v1 ->
+ exists v2, eval_addressing genv sp addr vl2 = Some v2 /\ Val.lessdef v1 v2.
+Proof.
+ intros. rewrite val_inject_list_lessdef in H.
+ assert (exists v2 : val,
+ eval_addressing genv sp addr vl2 = Some v2
+ /\ Val.inject (fun b => Some(b, 0)) v1 v2).
+ eapply eval_addressing_inj with (sp1 := sp).
+ intros. rewrite <- val_inject_lessdef; auto.
+ rewrite <- val_inject_lessdef; auto.
+ eauto. auto.
+ destruct H1 as [v2 [A B]]. exists v2; split; auto. rewrite val_inject_lessdef; auto.
+Qed.
+
+End EVAL_LESSDEF.
+
+(** Compatibility of the evaluation functions with memory injections. *)
+
+Section EVAL_INJECT.
+
+Variable F V: Type.
+Variable genv: Genv.t F V.
+Variable f: meminj.
+Hypothesis globals: meminj_preserves_globals genv f.
+Variable sp1: block.
+Variable sp2: block.
+Variable delta: Z.
+Hypothesis sp_inj: f sp1 = Some(sp2, delta).
+
+Remark symbol_address_inject:
+ forall id ofs, Val.inject f (Genv.symbol_address genv id ofs) (Genv.symbol_address genv id ofs).
+Proof.
+ intros. unfold Genv.symbol_address. destruct (Genv.find_symbol genv id) eqn:?; auto.
+ exploit (proj1 globals); eauto. intros.
+ econstructor; eauto. rewrite Ptrofs.add_zero; auto.
+Qed.
+
+Lemma eval_condition_inject:
+ forall cond vl1 vl2 b m1 m2,
+ Val.inject_list f vl1 vl2 ->
+ Mem.inject f m1 m2 ->
+ eval_condition cond vl1 m1 = Some b ->
+ eval_condition cond vl2 m2 = Some b.
+Proof.
+ intros. eapply eval_condition_inj with (f := f) (m1 := m1); eauto.
+ intros; eapply Mem.valid_pointer_inject_val; eauto.
+ intros; eapply Mem.weak_valid_pointer_inject_val; eauto.
+ intros; eapply Mem.weak_valid_pointer_inject_no_overflow; eauto.
+ intros; eapply Mem.different_pointers_inject; eauto.
+Qed.
+
+Lemma eval_addressing_inject:
+ forall addr vl1 vl2 v1,
+ Val.inject_list f vl1 vl2 ->
+ eval_addressing genv (Vptr sp1 Ptrofs.zero) addr vl1 = Some v1 ->
+ exists v2,
+ eval_addressing genv (Vptr sp2 Ptrofs.zero) (shift_stack_addressing delta addr) vl2 = Some v2
+ /\ Val.inject f v1 v2.
+Proof.
+ intros.
+ rewrite eval_shift_stack_addressing.
+ eapply eval_addressing_inj with (sp1 := Vptr sp1 Ptrofs.zero); eauto.
+ intros. apply symbol_address_inject.
+ econstructor; eauto. rewrite Ptrofs.add_zero_l; auto.
+Qed.
+
+Lemma eval_operation_inject:
+ forall op vl1 vl2 v1 m1 m2,
+ Val.inject_list f vl1 vl2 ->
+ Mem.inject f m1 m2 ->
+ eval_operation genv (Vptr sp1 Ptrofs.zero) op vl1 m1 = Some v1 ->
+ exists v2,
+ eval_operation genv (Vptr sp2 Ptrofs.zero) (shift_stack_operation delta op) vl2 m2 = Some v2
+ /\ Val.inject f v1 v2.
+Proof.
+ intros.
+ rewrite eval_shift_stack_operation. simpl.
+ eapply eval_operation_inj with (sp1 := Vptr sp1 Ptrofs.zero) (m1 := m1); eauto.
+ intros; eapply Mem.valid_pointer_inject_val; eauto.
+ intros; eapply Mem.weak_valid_pointer_inject_val; eauto.
+ intros; eapply Mem.weak_valid_pointer_inject_no_overflow; eauto.
+ intros; eapply Mem.different_pointers_inject; eauto.
+ intros. apply symbol_address_inject.
+ econstructor; eauto. rewrite Ptrofs.add_zero_l; auto.
+Qed.
+
+End EVAL_INJECT.
+
+(** * Handling of builtin arguments *)
+
+Definition builtin_arg_ok_1
+ (A: Type) (ba: builtin_arg A) (c: builtin_arg_constraint) :=
+ match c, ba with
+ | OK_all, _ => true
+ | OK_const, (BA_int _ | BA_long _ | BA_float _ | BA_single _) => true
+ | OK_addrstack, BA_addrstack _ => true
+ | OK_addressing, BA_addrstack _ => true
+ | OK_addressing, BA_addptr (BA _) (BA_int _) => true
+ | OK_addressing, BA_addptr (BA _) (BA_long _) => true
+ | _, _ => false
+ end.
+
+Definition builtin_arg_ok
+ (A: Type) (ba: builtin_arg A) (c: builtin_arg_constraint) :=
+ match ba with
+ | (BA _ | BA_splitlong (BA _) (BA _)) => true
+ | _ => builtin_arg_ok_1 ba c
+ end.
diff --git a/aarch64/PrintOp.ml b/aarch64/PrintOp.ml
new file mode 100644
index 00000000..1780104c
--- /dev/null
+++ b/aarch64/PrintOp.ml
@@ -0,0 +1,247 @@
+(* *********************************************************************)
+(* *)
+(* 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. *)
+(* *)
+(* *********************************************************************)
+
+(** Pretty-printing of operators, conditions, addressing modes *)
+
+open Printf
+open Camlcoq
+open Integers
+open Op
+
+let comparison_name = function
+ | Ceq -> "=="
+ | Cne -> "!="
+ | Clt -> "<"
+ | Cle -> "<="
+ | Cgt -> ">"
+ | Cge -> ">="
+
+let shift pp (s, a) =
+ match s with
+ | Slsl -> fprintf pp "<< %ld" (camlint_of_coqint a)
+ | Slsr -> fprintf pp ">>u %ld" (camlint_of_coqint a)
+ | Sasr -> fprintf pp ">>s %ld" (camlint_of_coqint a)
+ | Sror -> fprintf pp "ror %ld" (camlint_of_coqint a)
+
+let shiftl pp (s, a) =
+ match s with
+ | Slsl -> fprintf pp "<<l %ld" (camlint_of_coqint a)
+ | Slsr -> fprintf pp ">>lu %ld" (camlint_of_coqint a)
+ | Sasr -> fprintf pp ">>ls %ld" (camlint_of_coqint a)
+ | Sror -> fprintf pp "rorl %ld" (camlint_of_coqint a)
+
+let extend_name = function
+ | Xsgn32 -> "sext"
+ | Xuns32 -> "zext"
+
+let print_condition reg pp = function
+ | (Ccomp c, [r1;r2]) ->
+ fprintf pp "%a %ss %a" reg r1 (comparison_name c) reg r2
+ | (Ccompu c, [r1;r2]) ->
+ fprintf pp "%a %su %a" reg r1 (comparison_name c) reg r2
+ | (Ccompimm(c, n), [r1]) ->
+ fprintf pp "%a %ss %ld" reg r1 (comparison_name c) (camlint_of_coqint n)
+ | (Ccompuimm(c, n), [r1]) ->
+ fprintf pp "%a %su %ld" reg r1 (comparison_name c) (camlint_of_coqint n)
+ | (Ccompshift(c, s, a), [r1;r2]) ->
+ fprintf pp "%a %ss %a %a" reg r1 (comparison_name c) reg r2 shift (s, a)
+ | (Ccompushift(c, s, a), [r1;r2]) ->
+ fprintf pp "%a %su %a %a" reg r1 (comparison_name c) reg r2 shift (s, a)
+ | (Cmaskzero n, [r1]) ->
+ fprintf pp "%a & 0x%lx == 0" reg r1 (camlint_of_coqint n)
+ | (Cmasknotzero n, [r1]) ->
+ fprintf pp "%a & 0x%lx != 0" reg r1 (camlint_of_coqint n)
+ | (Ccompl c, [r1;r2]) ->
+ fprintf pp "%a %sls %a" reg r1 (comparison_name c) reg r2
+ | (Ccomplu c, [r1;r2]) ->
+ fprintf pp "%a %slu %a" reg r1 (comparison_name c) reg r2
+ | (Ccomplimm(c, n), [r1]) ->
+ fprintf pp "%a %sls %Ld" reg r1 (comparison_name c) (camlint64_of_coqint n)
+ | (Ccompluimm(c, n), [r1]) ->
+ fprintf pp "%a %slu %Ld" reg r1 (comparison_name c) (camlint64_of_coqint n)
+ | (Ccomplshift(c, s, a), [r1;r2]) ->
+ fprintf pp "%a %sls %a %a" reg r1 (comparison_name c) reg r2 shift (s, a)
+ | (Ccomplushift(c, s, a), [r1;r2]) ->
+ fprintf pp "%a %slu %a %a" reg r1 (comparison_name c) reg r2 shift (s, a)
+ | (Cmasklzero n, [r1]) ->
+ fprintf pp "%a & 0x%Lx == 0" reg r1 (camlint64_of_coqint n)
+ | (Cmasklnotzero n, [r1]) ->
+ fprintf pp "%a & 0x%Lx != 0" reg r1 (camlint64_of_coqint n)
+ | (Ccompf c, [r1;r2]) ->
+ fprintf pp "%a %sf %a" reg r1 (comparison_name c) reg r2
+ | (Cnotcompf c, [r1;r2]) ->
+ fprintf pp "%a not(%sf) %a" reg r1 (comparison_name c) reg r2
+ | (Ccompfzero c, [r1]) ->
+ fprintf pp "%a %sf 0.0" reg r1 (comparison_name c)
+ | (Cnotcompfzero c, [r1]) ->
+ fprintf pp "%a not(%sf) 0.0" reg r1 (comparison_name c)
+ | (Ccompfs c, [r1;r2]) ->
+ fprintf pp "%a %sfs %a" reg r1 (comparison_name c) reg r2
+ | (Cnotcompfs c, [r1;r2]) ->
+ fprintf pp "%a not(%sfs) %a" reg r1 (comparison_name c) reg r2
+ | (Ccompfszero c, [r1]) ->
+ fprintf pp "%a %sfs 0.0" reg r1 (comparison_name c)
+ | (Cnotcompfszero c, [r1]) ->
+ fprintf pp "%a not(%sfs) 0.0" reg r1 (comparison_name c)
+ | _ ->
+ fprintf pp "<bad condition>"
+
+let print_operation reg pp = function
+ | Omove, [r1] -> reg pp r1
+ | Ointconst n, [] -> fprintf pp "%ld" (camlint_of_coqint n)
+ | Olongconst n, [] -> fprintf pp "%LdL" (camlint64_of_coqint n)
+ | Ofloatconst n, [] -> fprintf pp "%F" (camlfloat_of_coqfloat n)
+ | Osingleconst n, [] -> fprintf pp "%Ff" (camlfloat_of_coqfloat32 n)
+ | Oaddrsymbol(id, ofs), [] ->
+ fprintf pp "\"%s\" + %Ld" (extern_atom id) (camlint64_of_ptrofs ofs)
+ | Oaddrstack ofs, [] ->
+ fprintf pp "stack(%Ld)" (camlint64_of_ptrofs ofs)
+(* 32-bit integer arithmetic *)
+ | Oshift(s, a), [r1] -> fprintf pp "%a %a" reg r1 shift (s,a)
+ | Oadd, [r1;r2] -> fprintf pp "%a + %a" reg r1 reg r2
+ | Oaddshift(s, a), [r1;r2] -> fprintf pp "%a + %a %a" reg r1 reg r2 shift (s,a)
+ | Oaddimm n, [r1] -> fprintf pp "%a + %ld" reg r1 (camlint_of_coqint n)
+ | Oneg, [r1] -> fprintf pp "- %a" reg r1
+ | Onegshift(s, a), [r1] -> fprintf pp "- (%a %a)" reg r1 shift (s,a)
+ | Osub, [r1;r2] -> fprintf pp "%a - %a" reg r1 reg r2
+ | Osubshift(s, a), [r1;r2] -> fprintf pp "%a - %a %a" reg r1 reg r2 shift (s,a)
+ | Omul, [r1;r2] -> fprintf pp "%a * %a" reg r1 reg r2
+ | Omuladd, [r1;r2;r3] -> fprintf pp "%a + %a * %a" reg r3 reg r1 reg r2
+ | Omulsub, [r1;r2;r3] -> fprintf pp "%a - %a * %a" reg r3 reg r1 reg r2
+ | Odiv, [r1;r2] -> fprintf pp "%a /s %a" reg r1 reg r2
+ | Odivu, [r1;r2] -> fprintf pp "%a /u %a" reg r1 reg r2
+ | Oand, [r1;r2] -> fprintf pp "%a & %a" reg r1 reg r2
+ | Oandshift(s, a), [r1;r2] -> fprintf pp "%a & %a %a" reg r1 reg r2 shift (s,a)
+ | Oandimm n, [r1] -> fprintf pp "%a & %ld" reg r1 (camlint_of_coqint n)
+ | Oor, [r1;r2] -> fprintf pp "%a | %a" reg r1 reg r2
+ | Oorshift(s, a), [r1;r2] -> fprintf pp "%a | %a %a" reg r1 reg r2 shift (s,a)
+ | Oorimm n, [r1] -> fprintf pp "%a | %ld" reg r1 (camlint_of_coqint n)
+ | Oxor, [r1;r2] -> fprintf pp "%a ^ %a" reg r1 reg r2
+ | Oxorshift(s, a), [r1;r2] -> fprintf pp "%a ^ %a %a" reg r1 reg r2 shift (s,a)
+ | Oxorimm n, [r1] -> fprintf pp "%a ^ %ld" reg r1 (camlint_of_coqint n)
+ | Onot, [r1] -> fprintf pp "~ %a" reg r1
+ | Onotshift(s, a), [r1] -> fprintf pp "~ (%a %a)" reg r1 shift (s,a)
+ | Obic, [r1;r2] -> fprintf pp "%a & ~ %a" reg r1 reg r2
+ | Obicshift(s, a), [r1;r2] -> fprintf pp "%a & ~ %a %a" reg r1 reg r2 shift (s,a)
+ | Oorn, [r1;r2] -> fprintf pp "%a | ~ %a" reg r1 reg r2
+ | Oornshift(s, a), [r1;r2] -> fprintf pp "%a | ~ %a %a" reg r1 reg r2 shift (s,a)
+ | Oeqv, [r1;r2] -> fprintf pp "%a ^ ~ %a" reg r1 reg r2
+ | Oeqvshift(s, a), [r1;r2] -> fprintf pp "%a ^ ~ %a %a" reg r1 reg r2 shift (s,a)
+ | Oshl, [r1;r2] -> fprintf pp "%a << %a" reg r1 reg r2
+ | Oshr, [r1;r2] -> fprintf pp "%a >>s %a" reg r1 reg r2
+ | Oshru, [r1;r2] -> fprintf pp "%a >>u %a" reg r1 reg r2
+ | Oshrximm n, [r1] -> fprintf pp "%a >>x %ld" reg r1 (camlint_of_coqint n)
+ | Ozext s, [r1] -> fprintf pp "zext(%d, %a)" (Z.to_int s) reg r1
+ | Osext s, [r1] -> fprintf pp "sext(%d, %a)" (Z.to_int s) reg r1
+ | Oshlzext(s, a), [r1] -> fprintf pp "zext(%d, %a) << %ld" (Z.to_int s) reg r1 (camlint_of_coqint a)
+ | Oshlsext(s, a), [r1] -> fprintf pp "sext(%d, %a) << %ld" (Z.to_int s) reg r1 (camlint_of_coqint a)
+ | Ozextshr(a, s), [r1] -> fprintf pp "zext(%d, %a >>u %ld)" (Z.to_int s) reg r1 (camlint_of_coqint a)
+ | Osextshr(a, s), [r1] -> fprintf pp "sext(%d, %a >>s %ld)" (Z.to_int s) reg r1 (camlint_of_coqint a)
+(* 64-bit integer arithmetic *)
+ | Oshiftl(s, a), [r1] -> fprintf pp "%a %a" reg r1 shiftl (s,a)
+ | Oextend(x, a), [r1] -> fprintf pp "%s(32, %a) <<l %ld" (extend_name x) reg r1 (camlint_of_coqint a)
+ | Omakelong, [r1;r2] -> fprintf pp "makelong(%a,%a)" reg r1 reg r2
+ | Olowlong, [r1] -> fprintf pp "lowlong(%a)" reg r1
+ | Ohighlong, [r1] -> fprintf pp "highlong(%a)" reg r1
+ | Oaddl, [r1;r2] -> fprintf pp "%a +l %a" reg r1 reg r2
+ | Oaddlshift(s, a), [r1;r2] -> fprintf pp "%a +l %a %a" reg r1 reg r2 shiftl (s,a)
+ | Oaddlext(x, a), [r1;r2] -> fprintf pp "%a +l %s(%a) << %ld" reg r1 (extend_name x) reg r2 (camlint_of_coqint a)
+ | Oaddlimm n, [r1] -> fprintf pp "%a +l %Ld" reg r1 (camlint64_of_coqint n)
+ | Onegl, [r1] -> fprintf pp "-l %a" reg r1
+ | Oneglshift(s, a), [r1] -> fprintf pp "-l (%a %a)" reg r1 shiftl (s,a)
+ | Osubl, [r1;r2] -> fprintf pp "%a -l %a" reg r1 reg r2
+ | Osublext(x, a), [r1;r2] -> fprintf pp "%a +l %s(%a) << %ld" reg r1 (extend_name x) reg r2 (camlint_of_coqint a)
+ | Osublshift(s, a), [r1;r2] -> fprintf pp "%a -l %a %a" reg r1 reg r2 shiftl (s,a)
+ | Omull, [r1;r2] -> fprintf pp "%a *l %a" reg r1 reg r2
+ | Omulladd, [r1;r2;r3] -> fprintf pp "%a +l %a *l %a" reg r3 reg r1 reg r2
+ | Omullsub, [r1;r2;r3] -> fprintf pp "%a -l %a *l %a" reg r3 reg r1 reg r2
+ | Omullhs, [r1;r2] -> fprintf pp "%a *hls %a" reg r1 reg r2
+ | Omullhu, [r1;r2] -> fprintf pp "%a *hlu %a" reg r1 reg r2
+ | Odivl, [r1;r2] -> fprintf pp "%a /ls %a" reg r1 reg r2
+ | Odivlu, [r1;r2] -> fprintf pp "%a /lu %a" reg r1 reg r2
+ | Oandl, [r1;r2] -> fprintf pp "%a &l %a" reg r1 reg r2
+ | Oandlshift(s, a), [r1;r2] -> fprintf pp "%a &l %a %a" reg r1 reg r2 shiftl (s,a)
+ | Oandlimm n, [r1] -> fprintf pp "%a &l %Ld" reg r1 (camlint64_of_coqint n)
+ | Oorl, [r1;r2] -> fprintf pp "%a |l %a" reg r1 reg r2
+ | Oorlshift(s, a), [r1;r2] -> fprintf pp "%a |l %a %a" reg r1 reg r2 shiftl (s,a)
+ | Oorlimm n, [r1] -> fprintf pp "%a |l %Ld" reg r1 (camlint64_of_coqint n)
+ | Oxorl, [r1;r2] -> fprintf pp "%a ^l %a" reg r1 reg r2
+ | Oxorlshift(s, a), [r1;r2] -> fprintf pp "%a ^l %a %a" reg r1 reg r2 shiftl (s,a)
+ | Oxorlimm n, [r1] -> fprintf pp "%a ^l %Ld" reg r1 (camlint64_of_coqint n)
+ | Onotl, [r1] -> fprintf pp "~l %a" reg r1
+ | Onotlshift(s, a), [r1] -> fprintf pp "~l (%a %a)" reg r1 shiftl (s,a)
+ | Obicl, [r1;r2] -> fprintf pp "%a &l ~l %a" reg r1 reg r2
+ | Obiclshift(s, a), [r1;r2] -> fprintf pp "%a &l ~l %a %a" reg r1 reg r2 shiftl (s,a)
+ | Oornl, [r1;r2] -> fprintf pp "%a |l ~l %a" reg r1 reg r2
+ | Oornlshift(s, a), [r1;r2] -> fprintf pp "%a |l ~l %a %a" reg r1 reg r2 shiftl (s,a)
+ | Oeqvl, [r1;r2] -> fprintf pp "%a ^l ~l %a" reg r1 reg r2
+ | Oeqvlshift(s, a), [r1;r2] -> fprintf pp "%a ^l ~l %a %a" reg r1 reg r2 shift (s,a)
+ | Oshll, [r1;r2] -> fprintf pp "%a <<l %a" reg r1 reg r2
+ | Oshrl, [r1;r2] -> fprintf pp "%a >>ls %a" reg r1 reg r2
+ | Oshrlu, [r1;r2] -> fprintf pp "%a >>lu %a" reg r1 reg r2
+ | Oshrlximm n, [r1] -> fprintf pp "%a >>lx %ld" reg r1 (camlint_of_coqint n)
+ | Ozextl s, [r1] -> fprintf pp "zextl(%d, %a)" (Z.to_int s) reg r1
+ | Osextl s, [r1] -> fprintf pp "sextl(%d, %a)" (Z.to_int s) reg r1
+ | Oshllzext(s, a), [r1] -> fprintf pp "zextl(%d, %a) <<l %ld" (Z.to_int s) reg r1 (camlint_of_coqint a)
+ | Oshllsext(s, a), [r1] -> fprintf pp "sextl(%d, %a) <<l %ld" (Z.to_int s) reg r1 (camlint_of_coqint a)
+ | Ozextshrl(a, s), [r1] -> fprintf pp "zextl(%d, %a >>lu %ld)" (Z.to_int s) reg r1 (camlint_of_coqint a)
+ | Osextshrl(a, s), [r1] -> fprintf pp "sextl(%d, %a >>ls %ld)" (Z.to_int s) reg r1 (camlint_of_coqint a)
+(* 64-bit floating-point arithmetic *)
+ | Onegf, [r1] -> fprintf pp "negf(%a)" reg r1
+ | Oabsf, [r1] -> fprintf pp "absf(%a)" reg r1
+ | Oaddf, [r1;r2] -> fprintf pp "%a +f %a" reg r1 reg r2
+ | Osubf, [r1;r2] -> fprintf pp "%a -f %a" reg r1 reg r2
+ | Omulf, [r1;r2] -> fprintf pp "%a *f %a" reg r1 reg r2
+ | Odivf, [r1;r2] -> fprintf pp "%a /f %a" reg r1 reg r2
+(* 32-bit floating-point arithmetic *)
+ | Onegfs, [r1] -> fprintf pp "negfs(%a)" reg r1
+ | Oabsfs, [r1] -> fprintf pp "absfs(%a)" reg r1
+ | Oaddfs, [r1;r2] -> fprintf pp "%a +fs %a" reg r1 reg r2
+ | Osubfs, [r1;r2] -> fprintf pp "%a -fs %a" reg r1 reg r2
+ | Omulfs, [r1;r2] -> fprintf pp "%a *fs %a" reg r1 reg r2
+ | Odivfs, [r1;r2] -> fprintf pp "%a /fs %a" reg r1 reg r2
+ | Osingleoffloat, [r1] -> fprintf pp "singleoffloat(%a)" reg r1
+ | Ofloatofsingle, [r1] -> fprintf pp "floatofsingle(%a)" reg r1
+(* Conversions between int and float *)
+ | Ointoffloat, [r1] -> fprintf pp "intoffloat(%a)" reg r1
+ | Ointuoffloat, [r1] -> fprintf pp "intuoffloat(%a)" reg r1
+ | Ofloatofint, [r1] -> fprintf pp "floatofint(%a)" reg r1
+ | Ofloatofintu, [r1] -> fprintf pp "floatofintu(%a)" reg r1
+ | Olongoffloat, [r1] -> fprintf pp "longoffloat(%a)" reg r1
+ | Olonguoffloat, [r1] -> fprintf pp "longuoffloat(%a)" reg r1
+ | Ofloatoflong, [r1] -> fprintf pp "floatoflong(%a)" reg r1
+ | Ofloatoflongu, [r1] -> fprintf pp "floatoflongu(%a)" reg r1
+ | Ointofsingle, [r1] -> fprintf pp "intofsingle(%a)" reg r1
+ | Ointuofsingle, [r1] -> fprintf pp "intuofsingle(%a)" reg r1
+ | Osingleofint, [r1] -> fprintf pp "singleofint(%a)" reg r1
+ | Osingleofintu, [r1] -> fprintf pp "singleofintu(%a)" reg r1
+ | Olongofsingle, [r1] -> fprintf pp "longofsingle(%a)" reg r1
+ | Olonguofsingle, [r1] -> fprintf pp "longuofsingle(%a)" reg r1
+ | Osingleoflong, [r1] -> fprintf pp "singleoflong(%a)" reg r1
+ | Osingleoflongu, [r1] -> fprintf pp "singleoflongu(%a)" reg r1
+(* Boolean tests *)
+ | Ocmp c, args -> print_condition reg pp (c, args)
+ | Osel (c, ty), r1::r2::args ->
+ fprintf pp "%a ?%s %a : %a"
+ (print_condition reg) (c, args)
+ (PrintAST.name_of_type ty) reg r1 reg r2
+ | _ -> fprintf pp "<bad operator>"
+
+let print_addressing reg pp = function
+ | Aindexed n, [r1] -> fprintf pp "%a + %Ld" reg r1 (camlint64_of_coqint n)
+ | Aindexed2, [r1; r2] -> fprintf pp "%a + %a" reg r1 reg r2
+ | Aindexed2shift a, [r1; r2] -> fprintf pp "%a + %a << %ld" reg r1 reg r2 (camlint_of_coqint a)
+ | Aindexed2ext(x, a), [r1; r2] -> fprintf pp "%a + %s(%a) << %ld" reg r1 (extend_name x) reg r2 (camlint_of_coqint a)
+ | Aglobal(id, ofs), [] ->
+ fprintf pp "\"%s\" + %Ld" (extern_atom id) (camlint64_of_ptrofs ofs)
+ | Ainstack ofs, [] -> fprintf pp "stack(%Ld)" (camlint64_of_ptrofs ofs)
+ | _ -> fprintf pp "<bad addressing>"
diff --git a/aarch64/SelectLong.vp b/aarch64/SelectLong.vp
new file mode 100644
index 00000000..ddf6e212
--- /dev/null
+++ b/aarch64/SelectLong.vp
@@ -0,0 +1,478 @@
+(* *********************************************************************)
+(* *)
+(* 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. *)
+(* *)
+(* *********************************************************************)
+
+(** Instruction selection for 64-bit integer operations *)
+
+Require Import Coqlib Zbits.
+Require Import Compopts AST Integers Floats.
+Require Import Op CminorSel SelectOp.
+
+Local Open Scope cminorsel_scope.
+
+(** ** Constants **)
+
+Definition longconst (n: int64) : expr :=
+ Eop (Olongconst n) Enil.
+
+(** ** Conversions *)
+
+Nondetfunction intoflong (e: expr) :=
+ match e with
+ | Eop (Olongconst n) Enil => Eop (Ointconst (Int.repr (Int64.unsigned n))) Enil
+ | _ => Eop Olowlong (e ::: Enil)
+ end.
+
+Nondetfunction longofint (e: expr) :=
+ match e with
+ | Eop (Ointconst n) Enil => longconst (Int64.repr (Int.signed n))
+ | _ => Eop (Oextend Xsgn32 (mk_amount64 Int.zero)) (e ::: Enil)
+ end.
+
+Nondetfunction longofintu (e: expr) :=
+ match e with
+ | Eop (Ointconst n) Enil => longconst (Int64.repr (Int.unsigned n))
+ | _ => Eop (Oextend Xuns32 (mk_amount64 Int.zero)) (e ::: Enil)
+ end.
+
+(** ** Integer addition and pointer addition *)
+
+Nondetfunction addlimm (n: int64) (e: expr) :=
+ if Int64.eq n Int64.zero then e else
+ match e with
+ | Eop (Olongconst m) Enil => longconst (Int64.add n m)
+ | Eop (Oaddrsymbol s m) Enil => Eop (Oaddrsymbol s (Ptrofs.add (Ptrofs.of_int64 n) m)) Enil
+ | Eop (Oaddrstack m) Enil => Eop (Oaddrstack (Ptrofs.add (Ptrofs.of_int64 n) m)) Enil
+ | Eop (Oaddlimm m) (t ::: Enil) => Eop (Oaddlimm(Int64.add n m)) (t ::: Enil)
+ | _ => Eop (Oaddlimm n) (e ::: Enil)
+ end.
+
+Nondetfunction addl (e1: expr) (e2: expr) :=
+ match e1, e2 with
+ | Eop (Olongconst n1) Enil, t2 => addlimm n1 t2
+ | t1, Eop (Olongconst n2) Enil => addlimm n2 t1
+ | Eop (Oaddlimm n1) (t1:::Enil), Eop (Oaddlimm n2) (t2:::Enil) =>
+ addlimm (Int64.add n1 n2) (Eop Oaddl (t1:::t2:::Enil))
+ | Eop (Oaddlimm n1) (t1:::Enil), Eop (Oaddrstack n2) Enil =>
+ Eop Oaddl (Eop (Oaddrstack (Ptrofs.add (Ptrofs.of_int64 n1) n2)) Enil ::: t1 ::: Enil)
+ | Eop (Oaddrstack n1) Enil, Eop (Oaddlimm n2) (t2:::Enil) =>
+ Eop Oaddl (Eop (Oaddrstack (Ptrofs.add n1 (Ptrofs.of_int64 n2))) Enil ::: t2 ::: Enil)
+ | Eop (Oaddlimm n1) (t1:::Enil), t2 =>
+ addlimm n1 (Eop Oaddl (t1:::t2:::Enil))
+ | t1, Eop (Oaddlimm n2) (t2:::Enil) =>
+ addlimm n2 (Eop Oaddl (t1:::t2:::Enil))
+ | Eop (Oshiftl s a) (t1:::Enil), t2 ?? arith_shift s =>
+ Eop (Oaddlshift s a) (t2 ::: t1 ::: Enil)
+ | t1, Eop (Oshiftl s a) (t2:::Enil) ?? arith_shift s =>
+ Eop (Oaddlshift s a) (t1 ::: t2 ::: Enil)
+ | Eop (Oextend x a) (t1:::Enil), t2 =>
+ Eop (Oaddlext x a) (t2 ::: t1 ::: Enil)
+ | t1, Eop (Oextend x a) (t2:::Enil) =>
+ Eop (Oaddlext x a) (t1 ::: t2 ::: Enil)
+ | Eop Omull (t1:::t2:::Enil), t3 =>
+ Eop Omulladd (t3:::t1:::t2:::Enil)
+ | t1, Eop Omull (t2:::t3:::Enil) =>
+ Eop Omulladd (t1:::t2:::t3:::Enil)
+ | _, _ => Eop Oaddl (e1:::e2:::Enil)
+ end.
+
+(** ** Opposite *)
+
+Nondetfunction negl (e: expr) :=
+ match e with
+ | Eop (Olongconst n) Enil => Eop (Olongconst (Int64.neg n)) Enil
+ | Eop (Oshiftl s a) (t1:::Enil) ?? arith_shift s => Eop (Oneglshift s a) (t1:::Enil)
+ | _ => Eop Onegl (e ::: Enil)
+ end.
+
+(** ** Integer and pointer subtraction *)
+
+Nondetfunction subl (e1: expr) (e2: expr) :=
+ match e1, e2 with
+ | t1, Eop (Olongconst n2) Enil =>
+ addlimm (Int64.neg n2) t1
+ | Eop (Oaddlimm n1) (t1:::Enil), Eop (Oaddlimm n2) (t2:::Enil) =>
+ addlimm (Int64.sub n1 n2) (Eop Osubl (t1:::t2:::Enil))
+ | Eop (Oaddlimm n1) (t1:::Enil), t2 =>
+ addlimm n1 (Eop Osubl (t1:::t2:::Enil))
+ | t1, Eop (Oaddlimm n2) (t2:::Enil) =>
+ addlimm (Int64.neg n2) (Eop Osubl (t1:::t2:::Enil))
+ | t1, Eop (Oshiftl s a) (t2:::Enil) ?? arith_shift s =>
+ Eop (Osublshift s a) (t1:::t2::: Enil)
+ | t1, Eop (Oextend x a) (t2:::Enil) =>
+ Eop (Osublext x a) (t1 ::: t2 ::: Enil)
+ | t1, Eop Omull (t2:::t3:::Enil) =>
+ Eop Omullsub (t1:::t2:::t3:::Enil)
+ | _, _ => Eop Osubl (e1:::e2:::Enil)
+ end.
+
+(** ** Immediate shift left *)
+
+Definition shllimm_base (e1: expr) (n: int) :=
+ Eop (Oshiftl Slsl (mk_amount64 n)) (e1 ::: Enil).
+
+Nondetfunction shllimm (e1: expr) (n: int) :=
+ if Int.eq n Int.zero then
+ e1
+ else if negb (Int.ltu n Int64.iwordsize') then
+ Eop Oshll (e1 ::: Eop (Ointconst n) Enil ::: Enil)
+ else match e1 with
+ | Eop (Olongconst n1) Enil =>
+ Eop (Olongconst (Int64.shl' n1 n)) Enil
+ | Eop (Oshiftl Slsl a) (t1:::Enil) =>
+ if Int.ltu (Int.add a n) Int64.iwordsize'
+ then shllimm_base t1 (Int.add a n)
+ else shllimm_base e1 n
+ | Eop (Ozextl s) (t1:::Enil) =>
+ Eop (Oshllzext s (mk_amount64 n)) (t1:::Enil)
+ | Eop (Osextl s) (t1:::Enil) =>
+ Eop (Oshllsext s (mk_amount64 n)) (t1:::Enil)
+ | Eop (Oshllzext s a) (t1:::Enil) =>
+ if Int.ltu (Int.add a n) Int64.iwordsize'
+ then Eop (Oshllzext s (mk_amount64 (Int.add a n))) (t1:::Enil)
+ else shllimm_base e1 n
+ | Eop (Oshllsext s a) (t1:::Enil) =>
+ if Int.ltu (Int.add a n) Int64.iwordsize'
+ then Eop (Oshllsext s (mk_amount64 (Int.add a n))) (t1:::Enil)
+ else shllimm_base e1 n
+ | Eop (Oextend x a) (t1:::Enil) =>
+ if Int.ltu (Int.add a n) Int64.iwordsize'
+ then Eop (Oextend x (mk_amount64 (Int.add a n))) (t1:::Enil)
+ else shllimm_base e1 n
+ | _ =>
+ shllimm_base e1 n
+ end.
+
+(** ** Immediate shift right (logical) *)
+
+Definition shrluimm_base (e1: expr) (n: int) :=
+ Eop (Oshiftl Slsr (mk_amount64 n)) (e1 ::: Enil).
+
+Nondetfunction shrluimm (e1: expr) (n: int) :=
+ if Int.eq n Int.zero then
+ e1
+ else if negb (Int.ltu n Int64.iwordsize') then
+ Eop Oshrlu (e1 ::: Eop (Ointconst n) Enil ::: Enil)
+ else match e1 with
+ | Eop (Olongconst n1) Enil =>
+ Eop (Olongconst (Int64.shru' n1 n)) Enil
+ | Eop (Oshiftl Slsl a) (t1:::Enil) =>
+ if Int.ltu n a
+ then Eop (Oshllzext (Int64.zwordsize - Int.unsigned a) (mk_amount64 (Int.sub a n))) (t1:::Enil)
+ else Eop (Ozextshrl (mk_amount64 (Int.sub n a)) (Int64.zwordsize - Int.unsigned n)) (t1:::Enil)
+ | Eop (Oshiftl Slsr a) (t1:::Enil) =>
+ if Int.ltu (Int.add a n) Int64.iwordsize'
+ then shrluimm_base t1 (Int.add a n)
+ else shrluimm_base e1 n
+ | Eop (Ozextl s) (t1:::Enil) =>
+ if zlt (Int.unsigned n) s
+ then Eop (Ozextshrl (mk_amount64 n) (s - Int.unsigned n)) (t1:::Enil)
+ else Eop (Olongconst Int64.zero) Enil
+ | _ =>
+ shrluimm_base e1 n
+ end.
+
+(** ** Immediate shift right (arithmetic) *)
+
+Definition shrlimm_base (e1: expr) (n: int) :=
+ Eop (Oshiftl Sasr (mk_amount64 n)) (e1 ::: Enil).
+
+Nondetfunction shrlimm (e1: expr) (n: int) :=
+ if Int.eq n Int.zero then
+ e1
+ else if negb (Int.ltu n Int64.iwordsize') then
+ Eop Oshrl (e1 ::: Eop (Ointconst n) Enil ::: Enil)
+ else match e1 with
+ | Eop (Olongconst n1) Enil =>
+ Eop (Olongconst (Int64.shr' n1 n)) Enil
+ | Eop (Oshiftl Slsl a) (t1:::Enil) =>
+ if Int.ltu n a
+ then Eop (Oshllsext (Int64.zwordsize - Int.unsigned a) (mk_amount64 (Int.sub a n))) (t1:::Enil)
+ else Eop (Osextshrl (mk_amount64 (Int.sub n a)) (Int64.zwordsize - Int.unsigned n)) (t1:::Enil)
+ | Eop (Oshiftl Sasr a) (t1:::Enil) =>
+ if Int.ltu (Int.add a n) Int64.iwordsize'
+ then shrlimm_base t1 (Int.add a n)
+ else shrlimm_base e1 n
+ | Eop (Osextl s) (t1:::Enil) =>
+ if zlt (Int.unsigned n) s && zlt s Int64.zwordsize
+ then Eop (Osextshrl (mk_amount64 n) (s - Int.unsigned n)) (t1:::Enil)
+ else shrlimm_base e1 n
+ | _ =>
+ shrlimm_base e1 n
+ end.
+
+(** ** Integer multiply *)
+
+Definition mullimm_base (n1: int64) (e2: expr) :=
+ match Int64.one_bits' n1 with
+ | i :: nil =>
+ shllimm e2 i
+ | i :: j :: nil =>
+ Elet e2 (addl (shllimm (Eletvar 0) i) (shllimm (Eletvar 0) j))
+ | _ =>
+ Eop Omull (Eop (Olongconst n1) Enil ::: e2 ::: Enil)
+ end.
+
+Nondetfunction mullimm (n1: int64) (e2: expr) :=
+ if Int64.eq n1 Int64.zero then Eop (Olongconst Int64.zero) Enil
+ else if Int64.eq n1 Int64.one then e2
+ else match e2 with
+ | Eop (Olongconst n2) Enil => Eop (Olongconst (Int64.mul n1 n2)) Enil
+ | Eop (Oaddlimm n2) (t2:::Enil) => addlimm (Int64.mul n1 n2) (mullimm_base n1 t2)
+ | _ => mullimm_base n1 e2
+ end.
+
+Nondetfunction mull (e1: expr) (e2: expr) :=
+ match e1, e2 with
+ | Eop (Olongconst n1) Enil, t2 => mullimm n1 t2
+ | t1, Eop (Olongconst n2) Enil => mullimm n2 t1
+ | _, _ => Eop Omull (e1:::e2:::Enil)
+ end.
+
+Definition mullhs (e1: expr) (n2: int64) :=
+ Eop Omullhs (e1 ::: longconst n2 ::: Enil).
+
+Definition mullhu (e1: expr) (n2: int64) :=
+ Eop Omullhu (e1 ::: longconst n2 ::: Enil).
+
+(** ** Integer conversions *)
+
+Nondetfunction zero_ext_l (sz: Z) (e: expr) :=
+ match e with
+ | Eop (Olongconst n) Enil => Eop (Olongconst (Int64.zero_ext sz n)) Enil
+ | Eop (Oshiftl Slsr a) (t1:::Enil) => Eop (Ozextshrl a sz) (t1:::Enil)
+ | Eop (Oshiftl Slsl a) (t1:::Enil) =>
+ if zlt (Int.unsigned a) sz
+ then Eop (Oshllzext (sz - Int.unsigned a) a) (t1:::Enil)
+ else Eop (Ozextl sz) (e:::Enil)
+ | _ => Eop (Ozextl sz) (e:::Enil)
+ end.
+
+(** ** Bitwise not *)
+
+Nondetfunction notl (e: expr) :=
+ match e with
+ | Eop (Olongconst n) Enil => Eop (Olongconst (Int64.not n)) Enil
+ | Eop (Oshiftl s a) (t1:::Enil) => Eop (Onotlshift s a) (t1:::Enil)
+ | Eop Onotl (t1:::Enil) => t1
+ | Eop (Onotlshift s a) (t1:::Enil) => Eop (Oshiftl s a) (t1:::Enil)
+ | Eop Obicl (t1:::t2:::Enil) => Eop Oornl (t2:::t1:::Enil)
+ | Eop Oornl (t1:::t2:::Enil) => Eop Obicl (t2:::t1:::Enil)
+ | Eop Oxorl (t1:::t2:::Enil) => Eop Oeqvl (t1:::t2:::Enil)
+ | Eop Oeqvl (t1:::t2:::Enil) => Eop Oxorl (t1:::t2:::Enil)
+ | _ => Eop Onotl (e:::Enil)
+ end.
+
+(** ** Bitwise and *)
+
+Definition andlimm_base (n1: int64) (e2: expr) :=
+ if Int64.eq n1 Int64.zero then Eop (Olongconst Int64.zero) Enil else
+ if Int64.eq n1 Int64.mone then e2 else
+ match Z_is_power2m1 (Int64.unsigned n1) with
+ | Some s => zero_ext_l s e2
+ | None => Eop (Oandlimm n1) (e2 ::: Enil)
+ end.
+
+Nondetfunction andlimm (n1: int64) (e2: expr) :=
+ match e2 with
+ | Eop (Olongconst n2) Enil => Eop (Olongconst (Int64.and n1 n2)) Enil
+ | Eop (Oandlimm n2) (t2:::Enil) => andlimm_base (Int64.and n1 n2) t2
+ | Eop (Ozextl s) (t2:::Enil) =>
+ if zle 0 s
+ then andlimm_base (Int64.and n1 (Int64.repr (two_p s - 1))) t2
+ else andlimm_base n1 e2
+ | _ => andlimm_base n1 e2
+ end.
+
+Nondetfunction andl (e1: expr) (e2: expr) :=
+ match e1, e2 with
+ | Eop (Olongconst n1) Enil, t2 => andlimm n1 t2
+ | t1, Eop (Olongconst n2) Enil => andlimm n2 t1
+ | Eop Onotl (t1:::Enil), t2 => Eop Obicl (t2:::t1:::Enil)
+ | t1, Eop Onotl (t2:::Enil) => Eop Obicl (t1:::t2:::Enil)
+ | Eop (Onotlshift s a) (t1:::Enil), t2 => Eop (Obiclshift s a) (t2:::t1:::Enil)
+ | t1, Eop (Onotlshift s a) (t2:::Enil) => Eop (Obiclshift s a) (t1:::t2:::Enil)
+ | Eop (Oshiftl s a) (t1:::Enil), t2 => Eop (Oandlshift s a) (t2:::t1:::Enil)
+ | t1, Eop (Oshiftl s a) (t2:::Enil) => Eop (Oandlshift s a) (t1:::t2:::Enil)
+ | _, _ => Eop Oandl (e1:::e2:::Enil)
+ end.
+
+(** ** Bitwise or *)
+
+Nondetfunction orlimm (n1: int64) (e2: expr) :=
+ if Int64.eq n1 Int64.zero then e2
+ else if Int64.eq n1 Int64.mone then Eop (Olongconst Int64.mone) Enil
+ else match e2 with
+ | Eop (Olongconst n2) Enil => Eop (Olongconst (Int64.or n1 n2)) Enil
+ | Eop (Oorlimm n2) (t2:::Enil) => Eop (Oorlimm (Int64.or n1 n2)) (t2:::Enil)
+ | _ => Eop (Oorlimm n1) (e2:::Enil)
+ end.
+
+Nondetfunction orl (e1: expr) (e2: expr) :=
+ match e1, e2 with
+ | Eop (Olongconst n1) Enil, t2 => orlimm n1 t2
+ | t1, Eop (Olongconst n2) Enil => orlimm n2 t1
+ | Eop Onotl (t1:::Enil), t2 => Eop Oornl (t2:::t1:::Enil)
+ | t1, Eop Onotl (t2:::Enil) => Eop Oornl (t1:::t2:::Enil)
+ | Eop (Onotlshift s a) (t1:::Enil), t2 => Eop (Oornlshift s a) (t2:::t1:::Enil)
+ | t1, Eop (Onotlshift s a) (t2:::Enil) => Eop (Oornlshift s a) (t1:::t2:::Enil)
+ | Eop (Oshiftl Slsl a1) (t1:::Enil), Eop (Oshiftl Slsr a2) (t2:::Enil) =>
+ if Int.eq (Int.add a1 a2) Int64.iwordsize' && same_expr_pure t1 t2
+ then Eop (Oshiftl Sror a2) (t2:::Enil)
+ else Eop (Oorlshift Slsr a2) (Eop (Oshiftl Slsl a1) (t1:::Enil):::t2:::Enil)
+ | Eop (Oshiftl Slsr a1) (t1:::Enil), Eop (Oshiftl Slsl a2) (t2:::Enil) =>
+ if Int.eq (Int.add a2 a1) Int64.iwordsize' && same_expr_pure t1 t2
+ then Eop (Oshiftl Sror a1) (t1:::Enil)
+ else Eop (Oorlshift Slsl a2) (Eop (Oshiftl Slsr a1) (t1:::Enil):::t2:::Enil)
+ | Eop (Oshiftl s a) (t1:::Enil), t2 => Eop (Oorlshift s a) (t2:::t1:::Enil)
+ | t1, Eop (Oshiftl s a) (t2:::Enil) => Eop (Oorlshift s a) (t1:::t2:::Enil)
+ | _, _ => Eop Oorl (e1:::e2:::Enil)
+ end.
+
+(** ** Bitwise xor *)
+
+Definition xorlimm_base (n1: int64) (e2: expr) :=
+ if Int64.eq n1 Int64.zero then e2 else
+ if Int64.eq n1 Int64.mone then notl e2 else
+ Eop (Oxorlimm n1) (e2:::Enil).
+
+Nondetfunction xorlimm (n1: int64) (e2: expr) :=
+ match e2 with
+ | Eop (Olongconst n2) Enil => Eop (Olongconst (Int64.xor n1 n2)) Enil
+ | Eop (Oxorlimm n2) (t2:::Enil) => xorlimm_base (Int64.xor n1 n2) t2
+ | _ => xorlimm_base n1 e2
+ end.
+
+Nondetfunction xorl (e1: expr) (e2: expr) :=
+ match e1, e2 with
+ | Eop (Olongconst n1) Enil, t2 => xorlimm n1 t2
+ | t1, Eop (Olongconst n2) Enil => xorlimm n2 t1
+ | Eop Onotl (t1:::Enil), t2 => Eop Oeqvl (t2:::t1:::Enil)
+ | t1, Eop Onotl (t2:::Enil) => Eop Oeqvl (t1:::t2:::Enil)
+ | Eop (Onotlshift s a) (t1:::Enil), t2 => Eop (Oeqvlshift s a) (t2:::t1:::Enil)
+ | t1, Eop (Onotlshift s a) (t2:::Enil) => Eop (Oeqvlshift s a) (t1:::t2:::Enil)
+ | Eop (Oshiftl s a) (t1:::Enil), t2 => Eop (Oxorlshift s a) (t2:::t1:::Enil)
+ | t1, Eop (Oshiftl s a) (t2:::Enil) => Eop (Oxorlshift s a) (t1:::t2:::Enil)
+ | _, _ => Eop Oxorl (e1:::e2:::Enil)
+ end.
+
+(** ** Integer division and modulus *)
+
+Definition modl_aux (divop: operation) (e1 e2: expr) :=
+ Elet e1
+ (Elet (lift e2)
+ (Eop Omullsub (Eletvar 1 :::
+ Eop divop (Eletvar 1 ::: Eletvar 0 ::: Enil) :::
+ Eletvar 0 :::
+ Enil))).
+
+Definition divls_base (e1: expr) (e2: expr) := Eop Odivl (e1:::e2:::Enil).
+Definition modls_base := modl_aux Odivl.
+Definition divlu_base (e1: expr) (e2: expr) := Eop Odivlu (e1:::e2:::Enil).
+Definition modlu_base := modl_aux Odivlu.
+
+Definition shrxlimm (e1: expr) (n2: int) :=
+ if Int.eq n2 Int.zero then e1 else Eop (Oshrlximm n2) (e1:::Enil).
+
+(** ** General shifts *)
+
+Nondetfunction shll (e1: expr) (e2: expr) :=
+ match e2 with
+ | Eop (Ointconst n2) Enil => shllimm e1 n2
+ | _ => Eop Oshll (e1:::e2:::Enil)
+ end.
+
+Nondetfunction shrl (e1: expr) (e2: expr) :=
+ match e2 with
+ | Eop (Ointconst n2) Enil => shrlimm e1 n2
+ | _ => Eop Oshrl (e1:::e2:::Enil)
+ end.
+
+Nondetfunction shrlu (e1: expr) (e2: expr) :=
+ match e2 with
+ | Eop (Ointconst n2) Enil => shrluimm e1 n2
+ | _ => Eop Oshrlu (e1:::e2:::Enil)
+ end.
+
+(** ** Comparisons *)
+
+Nondetfunction complimm (default: comparison -> int64 -> condition)
+ (sem: comparison -> int64 -> int64 -> bool)
+ (c: comparison) (e1: expr) (n2: int64) :=
+ match c, e1 with
+ | c, Eop (Olongconst n1) Enil =>
+ Eop (Ointconst (if sem c n1 n2 then Int.one else Int.zero)) Enil
+ | Ceq, Eop (Oandlimm m) (t1:::Enil) =>
+ if Int64.eq n2 Int64.zero
+ then Eop (Ocmp (Cmasklzero m)) (t1:::Enil)
+ else Eop (Ocmp (default c n2)) (e1:::Enil)
+ | Cne, Eop (Oandlimm m) (t1:::Enil) =>
+ if Int64.eq n2 Int64.zero
+ then Eop (Ocmp (Cmasklnotzero m)) (t1:::Enil)
+ else Eop (Ocmp (default c n2)) (e1:::Enil)
+ | _, _ =>
+ Eop (Ocmp (default c n2)) (e1:::Enil)
+ end.
+
+Nondetfunction cmpl (c: comparison) (e1: expr) (e2: expr) :=
+ match e1, e2 with
+ | Eop (Olongconst n1) Enil, t2 =>
+ complimm Ccomplimm Int64.cmp (swap_comparison c) t2 n1
+ | t1, Eop (Olongconst n2) Enil =>
+ complimm Ccomplimm Int64.cmp c t1 n2
+ | Eop (Oshiftl s a) (t1:::Enil), t2 ?? arith_shift s =>
+ Eop (Ocmp (Ccomplshift (swap_comparison c) s a)) (t2:::t1:::Enil)
+ | t1, Eop (Oshiftl s a) (t2:::Enil) ?? arith_shift s =>
+ Eop (Ocmp (Ccomplshift c s a)) (t1:::t2:::Enil)
+ | _, _ =>
+ Eop (Ocmp (Ccompl c)) (e1:::e2:::Enil)
+ end.
+
+Nondetfunction cmplu (c: comparison) (e1: expr) (e2: expr) :=
+ match e1, e2 with
+ | Eop (Olongconst n1) Enil, t2 =>
+ complimm Ccompluimm Int64.cmpu (swap_comparison c) t2 n1
+ | t1, Eop (Olongconst n2) Enil =>
+ complimm Ccompluimm Int64.cmpu c t1 n2
+ | Eop (Oshiftl s a) (t1:::Enil), t2 ?? arith_shift s =>
+ Eop (Ocmp (Ccomplushift (swap_comparison c) s a)) (t2:::t1:::Enil)
+ | t1, Eop (Oshiftl s a) (t2:::Enil) ?? arith_shift s =>
+ Eop (Ocmp (Ccomplushift c s a)) (t1:::t2:::Enil)
+ | _, _ =>
+ Eop (Ocmp (Ccomplu c)) (e1:::e2:::Enil)
+ end.
+
+(** ** Floating-point conversions *)
+
+Definition longoffloat (e: expr) :=
+ Eop Olongoffloat (e:::Enil).
+
+Definition longuoffloat (e: expr) :=
+ Eop Olonguoffloat (e:::Enil).
+
+Definition floatoflong (e: expr) :=
+ Eop Ofloatoflong (e:::Enil).
+
+Definition floatoflongu (e: expr) :=
+ Eop Ofloatoflongu (e:::Enil).
+
+Definition longofsingle (e: expr) :=
+ Eop Olongofsingle (e:::Enil).
+
+Definition longuofsingle (e: expr) :=
+ Eop Olonguofsingle (e:::Enil).
+
+Definition singleoflong (e: expr) :=
+ Eop Osingleoflong (e:::Enil).
+
+Definition singleoflongu (e: expr) :=
+ Eop Osingleoflongu (e:::Enil).
+
diff --git a/aarch64/SelectLongproof.v b/aarch64/SelectLongproof.v
new file mode 100644
index 00000000..b051369c
--- /dev/null
+++ b/aarch64/SelectLongproof.v
@@ -0,0 +1,764 @@
+(* *********************************************************************)
+(* *)
+(* 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 of instruction selection for 64-bit integer operators *)
+
+Require Import Coqlib Zbits.
+Require Import AST Integers Floats Values Memory Globalenvs.
+Require Import Cminor Op CminorSel.
+Require Import SelectOp SelectLong SelectOpproof.
+
+Local Open Scope cminorsel_scope.
+Local Transparent Archi.ptr64.
+
+(** * Correctness of the smart constructors *)
+
+Section CMCONSTR.
+
+Variable ge: genv.
+Variable sp: val.
+Variable e: env.
+Variable m: mem.
+
+Definition unary_constructor_sound (cstr: expr -> expr) (sem: val -> val) : Prop :=
+ forall le a x,
+ eval_expr ge sp e m le a x ->
+ exists v, eval_expr ge sp e m le (cstr a) v /\ Val.lessdef (sem x) v.
+
+Definition binary_constructor_sound (cstr: expr -> expr -> expr) (sem: val -> val -> val) : Prop :=
+ forall le a x b y,
+ eval_expr ge sp e m le a x ->
+ eval_expr ge sp e m le b y ->
+ exists v, eval_expr ge sp e m le (cstr a b) v /\ Val.lessdef (sem x y) v.
+
+Definition partial_unary_constructor_sound (cstr: expr -> expr) (sem: val -> option val) : Prop :=
+ forall le a x y,
+ eval_expr ge sp e m le a x ->
+ sem x = Some y ->
+ exists v, eval_expr ge sp e m le (cstr a) v /\ Val.lessdef y v.
+
+Definition partial_binary_constructor_sound (cstr: expr -> expr -> expr) (sem: val -> val -> option val) : Prop :=
+ forall le a x b y z,
+ eval_expr ge sp e m le a x ->
+ eval_expr ge sp e m le b y ->
+ sem x y = Some z ->
+ exists v, eval_expr ge sp e m le (cstr a b) v /\ Val.lessdef z v.
+
+(** ** Constants *)
+
+Theorem eval_longconst:
+ forall le n, eval_expr ge sp e m le (longconst n) (Vlong n).
+Proof.
+ intros; EvalOp.
+Qed.
+
+(** ** Conversions *)
+
+Theorem eval_intoflong: unary_constructor_sound intoflong Val.loword.
+Proof.
+ unfold intoflong; red; intros until x; destruct (intoflong_match a); intros; InvEval; subst.
+- TrivialExists.
+- TrivialExists.
+Qed.
+
+Theorem eval_longofintu: unary_constructor_sound longofintu Val.longofintu.
+Proof.
+ unfold longofintu; red; intros until x; destruct (longofintu_match a); intros; InvEval; subst.
+- TrivialExists.
+- TrivialExists. simpl. unfold eval_extend. rewrite mk_amount64_eq by reflexivity.
+ destruct x; simpl; auto. rewrite Int64.shl'_zero. auto.
+Qed.
+
+Theorem eval_longofint: unary_constructor_sound longofint Val.longofint.
+Proof.
+ unfold longofint; red; intros until x; destruct (longofint_match a); intros; InvEval; subst.
+- TrivialExists.
+- TrivialExists. simpl. unfold eval_extend. rewrite mk_amount64_eq by reflexivity.
+ destruct x; simpl; auto. rewrite Int64.shl'_zero. auto.
+Qed.
+
+(** ** Addition, opposite, subtraction *)
+
+Theorem eval_addlimm:
+ forall n, unary_constructor_sound (addlimm n) (fun x => Val.addl x (Vlong n)).
+Proof.
+ red; unfold addlimm; intros until x.
+ predSpec Int64.eq Int64.eq_spec n Int64.zero.
+- subst n. intros. exists x; split; auto.
+ destruct x; simpl; auto.
+ rewrite Int64.add_zero; auto.
+ rewrite Ptrofs.add_zero; auto.
+- case (addlimm_match a); intros; InvEval; subst.
++ rewrite Int64.add_commut; TrivialExists.
++ TrivialExists. simpl. rewrite Ptrofs.add_commut, Genv.shift_symbol_address_64; auto.
++ econstructor; split. EvalOp. destruct sp; simpl; auto.
+ rewrite Ptrofs.add_assoc, (Ptrofs.add_commut m0); auto.
++ rewrite Val.addl_assoc, Int64.add_commut; TrivialExists.
++ TrivialExists.
+Qed.
+
+Theorem eval_addl: binary_constructor_sound addl Val.addl.
+Proof.
+ red; intros until y.
+ unfold addl; case (addl_match a b); intros; InvEval; subst.
+- rewrite Val.addl_commut. apply eval_addlimm; auto.
+- apply eval_addlimm; auto.
+- replace (Val.addl (Val.addl v1 (Vlong n1)) (Val.addl v0 (Vlong n2)))
+ with (Val.addl (Val.addl v1 v0) (Val.addl (Vlong n1) (Vlong n2))).
+ apply eval_addlimm. EvalOp.
+ repeat rewrite Val.addl_assoc. decEq. apply Val.addl_permut.
+- TrivialExists. simpl.
+ rewrite Val.addl_commut, Val.addl_assoc. f_equal; f_equal.
+ destruct sp; simpl; auto. rewrite Ptrofs.add_assoc, (Ptrofs.add_commut n2). auto.
+- TrivialExists. simpl.
+ rewrite <- (Val.addl_commut v1), <- (Val.addl_commut (Val.addl v1 (Vlong n2))).
+ rewrite Val.addl_assoc. f_equal; f_equal.
+ destruct sp; simpl; auto. rewrite Ptrofs.add_assoc. auto.
+- replace (Val.addl (Val.addl v1 (Vlong n1)) y)
+ with (Val.addl (Val.addl v1 y) (Vlong n1)).
+ apply eval_addlimm. EvalOp.
+ repeat rewrite Val.addl_assoc. decEq. apply Val.addl_commut.
+- rewrite <- Val.addl_assoc. apply eval_addlimm. EvalOp.
+- rewrite Val.addl_commut. TrivialExists.
+- TrivialExists.
+- rewrite Val.addl_commut. TrivialExists.
+- TrivialExists.
+- rewrite Val.addl_commut. TrivialExists.
+- TrivialExists.
+- TrivialExists.
+Qed.
+
+Theorem eval_negl: unary_constructor_sound negl (fun v => Val.subl (Vlong Int64.zero) v).
+Proof.
+ red; intros until x; unfold negl. case (negl_match a); intros; InvEval; subst.
+- TrivialExists.
+- TrivialExists.
+- TrivialExists.
+Qed.
+
+Theorem eval_subl: binary_constructor_sound subl Val.subl.
+Proof.
+ red; intros until y; unfold subl; case (subl_match a b); intros; InvEval; subst.
+- rewrite Val.subl_addl_opp. apply eval_addlimm; auto.
+- rewrite Val.subl_addl_l. rewrite Val.subl_addl_r.
+ rewrite Val.addl_assoc. simpl. rewrite Int64.add_commut. rewrite <- Int64.sub_add_opp.
+ apply eval_addlimm; EvalOp.
+- rewrite Val.subl_addl_l. apply eval_addlimm; EvalOp.
+- rewrite Val.subl_addl_r. apply eval_addlimm; EvalOp.
+- TrivialExists.
+- TrivialExists.
+- TrivialExists.
+- TrivialExists.
+Qed.
+
+(** ** Immediate shifts *)
+
+Remark eval_shllimm_base: forall le a n x,
+ eval_expr ge sp e m le a x ->
+ Int.ltu n Int64.iwordsize' = true ->
+ eval_expr ge sp e m le (shllimm_base a n) (Val.shll x (Vint n)).
+Proof.
+Local Opaque mk_amount64.
+ unfold shlimm_base; intros; EvalOp. simpl. rewrite mk_amount64_eq by auto. auto.
+Qed.
+
+Theorem eval_shllimm:
+ forall n, unary_constructor_sound (fun a => shllimm a n)
+ (fun x => Val.shll x (Vint n)).
+Proof.
+ red; intros until x; unfold shllimm.
+ predSpec Int.eq Int.eq_spec n Int.zero; [| destruct (Int.ltu n Int64.iwordsize') eqn:L]; simpl.
+- intros; subst. exists x; split; auto. destruct x; simpl; auto. rewrite Int64.shl'_zero; auto.
+- destruct (shllimm_match a); intros; InvEval; subst.
++ TrivialExists. simpl; rewrite L; auto.
++ destruct (Int.ltu (Int.add a n) Int64.iwordsize') eqn:L2.
+* econstructor; split. eapply eval_shllimm_base; eauto.
+ destruct v1; simpl; auto. rewrite a64_range; simpl. rewrite L, L2.
+ rewrite Int64.shl'_shl'; auto using a64_range.
+* econstructor; split; [|eauto]. apply eval_shllimm_base; auto. EvalOp.
++ TrivialExists. simpl. rewrite mk_amount64_eq; auto.
++ TrivialExists. simpl. rewrite mk_amount64_eq; auto.
++ destruct (Int.ltu (Int.add a n) Int64.iwordsize') eqn:L2.
+* TrivialExists. simpl. rewrite mk_amount64_eq by auto.
+ destruct (Val.zero_ext_l s v1); simpl; auto.
+ rewrite a64_range; simpl; rewrite L, L2.
+ rewrite Int64.shl'_shl'; auto using a64_range.
+* econstructor; split. eapply eval_shllimm_base; eauto. EvalOp; simpl; eauto. auto.
++ destruct (Int.ltu (Int.add a n) Int64.iwordsize') eqn:L2.
+* TrivialExists. simpl. rewrite mk_amount64_eq by auto.
+ destruct (Val.sign_ext_l s v1); simpl; auto.
+ rewrite a64_range; simpl; rewrite L, L2.
+ rewrite Int64.shl'_shl'; auto using a64_range.
+* econstructor; split. eapply eval_shllimm_base; eauto. EvalOp; simpl; eauto. auto.
++ destruct (Int.ltu (Int.add a n) Int64.iwordsize') eqn:L2.
+* TrivialExists. simpl. unfold eval_extend. rewrite mk_amount64_eq by auto.
+ destruct (match x0 with Xsgn32 => Val.longofint v1 | Xuns32 => Val.longofintu v1 end); simpl; auto.
+ rewrite a64_range; simpl; rewrite L, L2.
+ rewrite Int64.shl'_shl'; auto using a64_range.
+* econstructor; split. eapply eval_shllimm_base; eauto. EvalOp; simpl; eauto. auto.
++ econstructor; eauto using eval_shllimm_base.
+- intros; TrivialExists.
+Qed.
+
+Remark eval_shrluimm_base: forall le a n x,
+ eval_expr ge sp e m le a x ->
+ Int.ltu n Int64.iwordsize' = true ->
+ eval_expr ge sp e m le (shrluimm_base a n) (Val.shrlu x (Vint n)).
+Proof.
+ unfold shrluimm_base; intros; EvalOp. simpl. rewrite mk_amount64_eq by auto. auto.
+Qed.
+
+Remark sub_shift_amount:
+ forall y z,
+ Int.ltu y Int64.iwordsize' = true -> Int.ltu z Int64.iwordsize' = true -> Int.unsigned y <= Int.unsigned z ->
+ Int.ltu (Int.sub z y) Int64.iwordsize' = true.
+Proof.
+ intros. unfold Int.ltu; apply zlt_true.
+ apply Int.ltu_inv in H. apply Int.ltu_inv in H0.
+ change (Int.unsigned Int64.iwordsize') with Int64.zwordsize in *.
+ unfold Int.sub; rewrite Int.unsigned_repr. omega.
+ assert (Int64.zwordsize < Int.max_unsigned) by reflexivity. omega.
+Qed.
+
+Theorem eval_shrluimm:
+ forall n, unary_constructor_sound (fun a => shrluimm a n)
+ (fun x => Val.shrlu x (Vint n)).
+Proof.
+Local Opaque Int64.zwordsize.
+ red; intros until x; unfold shrluimm.
+ predSpec Int.eq Int.eq_spec n Int.zero; [| destruct (Int.ltu n Int64.iwordsize') eqn:L]; simpl.
+- intros; subst. exists x; split; auto. destruct x; simpl; auto. rewrite Int64.shru'_zero; auto.
+- destruct (shrluimm_match a); intros; InvEval; subst.
++ TrivialExists. simpl; rewrite L; auto.
++ destruct (Int.ltu n a) eqn:L2.
+* assert (L3: Int.ltu (Int.sub a n) Int64.iwordsize' = true).
+ { apply sub_shift_amount; auto using a64_range.
+ apply Int.ltu_inv in L2. omega. }
+ econstructor; split. EvalOp.
+ destruct v1; simpl; auto. rewrite mk_amount64_eq, L3, a64_range by auto.
+ simpl. rewrite L. rewrite Int64.shru'_shl', L2 by auto using a64_range. auto.
+* assert (L3: Int.ltu (Int.sub n a) Int64.iwordsize' = true).
+ { apply sub_shift_amount; auto using a64_range.
+ unfold Int.ltu in L2. destruct zlt in L2; discriminate || omega. }
+ econstructor; split. EvalOp.
+ destruct v1; simpl; auto. rewrite mk_amount64_eq, L3, a64_range by auto.
+ simpl. rewrite L. rewrite Int64.shru'_shl', L2 by auto using a64_range. auto.
++ destruct (Int.ltu (Int.add a n) Int64.iwordsize') eqn:L2.
+* econstructor; split. eapply eval_shrluimm_base; eauto.
+ destruct v1; simpl; auto. rewrite a64_range; simpl. rewrite L, L2.
+ rewrite Int64.shru'_shru'; auto using a64_range.
+* econstructor; split; [|eauto]. apply eval_shrluimm_base; auto. EvalOp.
++ destruct (zlt (Int.unsigned n) s).
+* econstructor; split. EvalOp. rewrite mk_amount64_eq by auto.
+ destruct v1; simpl; auto. rewrite ! L; simpl.
+ set (s' := s - Int.unsigned n).
+ replace s with (s' + Int.unsigned n) by (unfold s'; omega).
+ rewrite Int64.shru'_zero_ext. auto. unfold s'; omega.
+* econstructor; split. EvalOp.
+ destruct v1; simpl; auto. rewrite ! L; simpl.
+ rewrite Int64.shru'_zero_ext_0 by omega. auto.
++ econstructor; eauto using eval_shrluimm_base.
+- intros; TrivialExists.
+Qed.
+
+Remark eval_shrlimm_base: forall le a n x,
+ eval_expr ge sp e m le a x ->
+ Int.ltu n Int64.iwordsize' = true ->
+ eval_expr ge sp e m le (shrlimm_base a n) (Val.shrl x (Vint n)).
+Proof.
+ unfold shrlimm_base; intros; EvalOp. simpl. rewrite mk_amount64_eq by auto. auto.
+Qed.
+
+Theorem eval_shrlimm:
+ forall n, unary_constructor_sound (fun a => shrlimm a n)
+ (fun x => Val.shrl x (Vint n)).
+Proof.
+ red; intros until x; unfold shrlimm.
+ predSpec Int.eq Int.eq_spec n Int.zero; [| destruct (Int.ltu n Int64.iwordsize') eqn:L]; simpl.
+- intros; subst. exists x; split; auto. destruct x; simpl; auto. rewrite Int64.shr'_zero; auto.
+- destruct (shrlimm_match a); intros; InvEval; subst.
++ TrivialExists. simpl; rewrite L; auto.
++ destruct (Int.ltu n a) eqn:L2.
+* assert (L3: Int.ltu (Int.sub a n) Int64.iwordsize' = true).
+ { apply sub_shift_amount; auto using a64_range.
+ apply Int.ltu_inv in L2. omega. }
+ econstructor; split. EvalOp.
+ destruct v1; simpl; auto. rewrite mk_amount64_eq, L3, a64_range by auto.
+ simpl. rewrite L. rewrite Int64.shr'_shl', L2 by auto using a64_range. auto.
+* assert (L3: Int.ltu (Int.sub n a) Int64.iwordsize' = true).
+ { apply sub_shift_amount; auto using a64_range.
+ unfold Int.ltu in L2. destruct zlt in L2; discriminate || omega. }
+ econstructor; split. EvalOp.
+ destruct v1; simpl; auto. rewrite mk_amount64_eq, L3, a64_range by auto.
+ simpl. rewrite L. rewrite Int64.shr'_shl', L2 by auto using a64_range. auto.
++ destruct (Int.ltu (Int.add a n) Int64.iwordsize') eqn:L2.
+* econstructor; split. eapply eval_shrlimm_base; eauto.
+ destruct v1; simpl; auto. rewrite a64_range; simpl. rewrite L, L2.
+ rewrite Int64.shr'_shr'; auto using a64_range.
+* econstructor; split; [|eauto]. apply eval_shrlimm_base; auto. EvalOp.
++ destruct (zlt (Int.unsigned n) s && zlt s Int64.zwordsize) eqn:E.
+* InvBooleans. econstructor; split. EvalOp. rewrite mk_amount64_eq by auto.
+ destruct v1; simpl; auto. rewrite ! L; simpl.
+ set (s' := s - Int.unsigned n).
+ replace s with (s' + Int.unsigned n) by (unfold s'; omega).
+ rewrite Int64.shr'_sign_ext. auto. unfold s'; omega. unfold s'; omega.
+* econstructor; split; [|eauto]. apply eval_shrlimm_base; auto. EvalOp.
++ econstructor; eauto using eval_shrlimm_base.
+- intros; TrivialExists.
+Qed.
+
+(** ** Multiplication *)
+
+Lemma eval_mullimm_base:
+ forall n, unary_constructor_sound (mullimm_base n) (fun x => Val.mull x (Vlong n)).
+Proof.
+ intros; red; intros; unfold mullimm_base.
+ assert (DFL: exists v, eval_expr ge sp e m le (Eop Omull (Eop (Olongconst n) Enil ::: a ::: Enil)) v /\ Val.lessdef (Val.mull x (Vlong n)) v).
+ { rewrite Val.mull_commut; TrivialExists. }
+ generalize (Int64.one_bits'_decomp n); generalize (Int64.one_bits'_range n);
+ destruct (Int64.one_bits' n) as [ | i [ | j []]]; intros P Q.
+- apply DFL.
+- replace (Val.mull x (Vlong n)) with (Val.shll x (Vint i)).
+ apply eval_shllimm; auto.
+ simpl in Q. destruct x; auto; simpl. rewrite P by auto with coqlib.
+ rewrite Q, Int64.add_zero, Int64.shl'_mul. auto.
+- exploit (eval_shllimm i (x :: le) (Eletvar 0) x). constructor; auto. intros [v1 [A1 B1]].
+ exploit (eval_shllimm j (x :: le) (Eletvar 0) x). constructor; auto. intros [v2 [A2 B2]].
+ exploit (eval_addl (x :: le)). eexact A1. eexact A2. intros [v [A B]].
+ exists v; split. econstructor; eauto.
+ simpl in Q. rewrite Q, Int64.add_zero. eapply Val.lessdef_trans; [|eexact B].
+ eapply Val.lessdef_trans; [|eapply Val.addl_lessdef; eauto].
+ destruct x; simpl; auto; rewrite ! P by auto with coqlib.
+ rewrite Int64.mul_add_distr_r, <- ! Int64.shl'_mul. auto.
+- apply DFL.
+Qed.
+
+Theorem eval_mullimm:
+ forall n, unary_constructor_sound (mullimm n) (fun x => Val.mull x (Vlong n)).
+Proof.
+ intros; red; intros until x; unfold mullimm.
+ predSpec Int64.eq Int64.eq_spec n Int64.zero.
+ intros. exists (Vlong Int64.zero); split. EvalOp.
+ destruct x; simpl; auto. subst n. rewrite Int64.mul_zero. auto.
+ predSpec Int64.eq Int64.eq_spec n Int64.one.
+ intros. exists x; split; auto.
+ destruct x; simpl; auto. subst n. rewrite Int64.mul_one. auto.
+ case (mullimm_match a); intros; InvEval; subst.
+- TrivialExists. simpl. rewrite Int64.mul_commut; auto.
+- rewrite Val.mull_addl_distr_l.
+ exploit eval_mullimm_base; eauto. instantiate (1 := n). intros [v' [A1 B1]].
+ exploit (eval_addlimm (Int64.mul n n2) le (mullimm_base n t2) v'). auto. intros [v'' [A2 B2]].
+ exists v''; split; auto. eapply Val.lessdef_trans. eapply Val.addl_lessdef; eauto.
+ rewrite Val.mull_commut; auto.
+- apply eval_mullimm_base; auto.
+Qed.
+
+Theorem eval_mull: binary_constructor_sound mull Val.mull.
+Proof.
+ red; intros until y; unfold mull; case (mull_match a b); intros; InvEval; subst.
+- rewrite Val.mull_commut. apply eval_mullimm; auto.
+- apply eval_mullimm; auto.
+- TrivialExists.
+Qed.
+
+Theorem eval_mullhu:
+ forall n, unary_constructor_sound (fun a => mullhu a n) (fun v => Val.mullhu v (Vlong n)).
+Proof.
+ unfold mullhu; red; intros; TrivialExists.
+Qed.
+
+Theorem eval_mullhs:
+ forall n, unary_constructor_sound (fun a => mullhs a n) (fun v => Val.mullhs v (Vlong n)).
+Proof.
+ unfold mullhs; red; intros; TrivialExists.
+Qed.
+
+(** Integer conversions *)
+
+Theorem eval_zero_ext_l:
+ forall sz, 0 <= sz -> unary_constructor_sound (zero_ext_l sz) (Val.zero_ext_l sz).
+Proof.
+ intros; red; intros until x; unfold zero_ext_l; case (zero_ext_l_match a); intros; InvEval; subst.
+- TrivialExists.
+- TrivialExists.
+- destruct (zlt (Int.unsigned a0) sz).
++ econstructor; split. EvalOp. destruct v1; simpl; auto. rewrite a64_range; simpl.
+ apply Val.lessdef_same. f_equal. rewrite Int64.shl'_zero_ext by omega. f_equal. omega.
++ TrivialExists.
+- TrivialExists.
+Qed.
+
+(** Bitwise not, and, or, xor *)
+
+Theorem eval_notl: unary_constructor_sound notl Val.notl.
+Proof.
+ assert (INV: forall v, Val.lessdef (Val.notl (Val.notl v)) v).
+ { destruct v; auto. simpl; rewrite Int64.not_involutive; auto. }
+ unfold notl; red; intros until x; case (notl_match a); intros; InvEval; subst.
+- TrivialExists.
+- TrivialExists.
+- exists v1; auto.
+- exists (eval_shiftl s v1 a0); split; auto. EvalOp.
+- econstructor; split. EvalOp.
+ destruct v1; simpl; auto; destruct v0; simpl; auto.
+ rewrite Int64.not_and_or_not, Int64.not_involutive, Int64.or_commut. auto.
+- econstructor; split. EvalOp.
+ destruct v1; simpl; auto; destruct v0; simpl; auto.
+ rewrite Int64.not_or_and_not, Int64.not_involutive, Int64.and_commut. auto.
+- econstructor; split. EvalOp.
+ destruct v1; simpl; auto; destruct v0; simpl; auto.
+ unfold Int64.not; rewrite ! Int64.xor_assoc. auto.
+- econstructor; split. EvalOp.
+ destruct v1; simpl; auto; destruct v0; simpl; auto.
+ unfold Int64.not; rewrite ! Int64.xor_assoc, Int64.xor_idem, Int64.xor_zero. auto.
+- TrivialExists.
+Qed.
+
+Lemma eval_andlimm_base:
+ forall n, unary_constructor_sound (andlimm_base n) (fun x => Val.andl x (Vlong n)).
+Proof.
+ intros; red; intros. unfold andlimm_base.
+ predSpec Int64.eq Int64.eq_spec n Int64.zero.
+ exists (Vlong Int64.zero); split. EvalOp.
+ destruct x; simpl; auto. subst n. rewrite Int64.and_zero. auto.
+ predSpec Int64.eq Int64.eq_spec n Int64.mone.
+ exists x; split; auto.
+ subst. destruct x; simpl; auto. rewrite Int64.and_mone; auto.
+ destruct (Z_is_power2m1 (Int64.unsigned n)) as [s|] eqn:P.
+ assert (0 <= s) by (eapply Z_is_power2m1_nonneg; eauto).
+ rewrite <- (Int64.repr_unsigned n), (Z_is_power2m1_sound _ _ P), <- Val.zero_ext_andl by auto.
+ apply eval_zero_ext_l; auto.
+ TrivialExists.
+Qed.
+
+Theorem eval_andlimm:
+ forall n, unary_constructor_sound (andlimm n) (fun x => Val.andl x (Vlong n)).
+Proof.
+ intros; red; intros until x. unfold andlimm.
+ case (andlimm_match a); intros; InvEval; subst.
+- rewrite Int64.and_commut; TrivialExists.
+- rewrite Val.andl_assoc, Int64.and_commut. apply eval_andlimm_base; auto.
+- destruct (zle 0 s).
++ replace (Val.zero_ext_l s v1) with (Val.andl v1 (Vlong (Int64.repr (two_p s - 1)))).
+ rewrite Val.andl_assoc, Int64.and_commut.
+ apply eval_andlimm_base; auto.
+ destruct v1; simpl; auto. rewrite Int64.zero_ext_and by auto. auto.
++ apply eval_andlimm_base. EvalOp.
+- apply eval_andlimm_base; auto.
+Qed.
+
+Theorem eval_andl: binary_constructor_sound andl Val.andl.
+Proof.
+ red; intros until y; unfold andl; case (andl_match a b); intros; InvEval; subst.
+- rewrite Val.andl_commut; apply eval_andlimm; auto.
+- apply eval_andlimm; auto.
+- rewrite Val.andl_commut; TrivialExists.
+- TrivialExists.
+- rewrite Val.andl_commut; TrivialExists.
+- TrivialExists.
+- rewrite Val.andl_commut; TrivialExists.
+- TrivialExists.
+- TrivialExists.
+Qed.
+
+Theorem eval_orlimm:
+ forall n, unary_constructor_sound (orlimm n) (fun x => Val.orl x (Vlong n)).
+Proof.
+ intros; red; intros until x. unfold orlimm.
+ predSpec Int64.eq Int64.eq_spec n Int64.zero.
+ intros. subst. exists x; split; auto.
+ destruct x; simpl; auto. rewrite Int64.or_zero; auto.
+ predSpec Int64.eq Int64.eq_spec n Int64.mone.
+ intros. exists (Vlong Int64.mone); split. EvalOp.
+ destruct x; simpl; auto. subst n. rewrite Int64.or_mone. auto.
+ destruct (orlimm_match a); intros; InvEval; subst.
+- rewrite Int64.or_commut; TrivialExists.
+- rewrite Val.orl_assoc, Int64.or_commut; TrivialExists.
+- TrivialExists.
+Qed.
+
+Theorem eval_orl: binary_constructor_sound orl Val.orl.
+Proof.
+ red; intros until y; unfold orl; case (orl_match a b); intros; InvEval; subst.
+- rewrite Val.orl_commut. apply eval_orlimm; auto.
+- apply eval_orlimm; auto.
+- rewrite Val.orl_commut; TrivialExists.
+- TrivialExists.
+- rewrite Val.orl_commut; TrivialExists.
+- TrivialExists.
+- (* shl - shru *)
+ destruct (Int.eq (Int.add a1 a2) Int64.iwordsize' && same_expr_pure t1 t2) eqn:?.
++ InvBooleans. apply Int.same_if_eq in H.
+ exploit eval_same_expr; eauto. intros [EQ1 EQ2]. subst.
+ econstructor; split. EvalOp.
+ destruct v0; simpl; auto. rewrite ! a64_range. simpl. rewrite <- Int64.or_ror'; auto using a64_range.
++ TrivialExists.
+- (* shru - shl *)
+ destruct (Int.eq (Int.add a2 a1) Int64.iwordsize' && same_expr_pure t1 t2) eqn:?.
++ InvBooleans. apply Int.same_if_eq in H.
+ exploit eval_same_expr; eauto. intros [EQ1 EQ2]. subst.
+ econstructor; split. EvalOp.
+ destruct v0; simpl; auto. rewrite ! a64_range. simpl.
+ rewrite Int64.or_commut, <- Int64.or_ror'; auto using a64_range.
++ TrivialExists.
+- rewrite Val.orl_commut; TrivialExists.
+- TrivialExists.
+- TrivialExists.
+Qed.
+
+Lemma eval_xorlimm_base:
+ forall n, unary_constructor_sound (xorlimm_base n) (fun x => Val.xorl x (Vlong n)).
+Proof.
+ intros; red; intros. unfold xorlimm_base.
+ predSpec Int64.eq Int64.eq_spec n Int64.zero.
+ intros. exists x; split. auto.
+ destruct x; simpl; auto. subst n. rewrite Int64.xor_zero. auto.
+ predSpec Int64.eq Int64.eq_spec n Int64.mone.
+ subst n. change (Val.xorl x (Vlong Int64.mone)) with (Val.notl x). apply eval_notl; auto.
+ TrivialExists.
+Qed.
+
+Theorem eval_xorlimm:
+ forall n, unary_constructor_sound (xorlimm n) (fun x => Val.xorl x (Vlong n)).
+Proof.
+ intros; red; intros until x. unfold xorlimm.
+ destruct (xorlimm_match a); intros; InvEval; subst.
+- rewrite Int64.xor_commut; TrivialExists.
+- rewrite Val.xorl_assoc; simpl. rewrite (Int64.xor_commut n2). apply eval_xorlimm_base; auto.
+- apply eval_xorlimm_base; auto.
+Qed.
+
+Theorem eval_xorl: binary_constructor_sound xorl Val.xorl.
+Proof.
+ red; intros until y; unfold xorl; case (xorl_match a b); intros; InvEval; subst.
+- rewrite Val.xorl_commut; apply eval_xorlimm; auto.
+- apply eval_xorlimm; auto.
+- rewrite Val.xorl_commut; TrivialExists.
+- TrivialExists.
+- rewrite Val.xorl_commut; TrivialExists.
+- TrivialExists.
+- rewrite Val.xorl_commut; TrivialExists.
+- TrivialExists.
+- TrivialExists.
+Qed.
+
+(** ** Integer division and modulus *)
+
+Theorem eval_divls_base: partial_binary_constructor_sound divls_base Val.divls.
+Proof.
+ red; intros; unfold divls_base; TrivialExists.
+Qed.
+
+Theorem eval_modls_base: partial_binary_constructor_sound modls_base Val.modls.
+Proof.
+ red; intros; unfold modls_base, modl_aux.
+ exploit Val.modls_divls; eauto. intros (q & A & B). subst z.
+ TrivialExists. repeat (econstructor; eauto with evalexpr). exact A.
+Qed.
+
+Theorem eval_divlu_base: partial_binary_constructor_sound divlu_base Val.divlu.
+Proof.
+ red; intros; unfold divlu_base; TrivialExists.
+Qed.
+
+Theorem eval_modlu_base: partial_binary_constructor_sound modlu_base Val.modlu.
+Proof.
+ red; intros; unfold modlu_base, modl_aux.
+ exploit Val.modlu_divlu; eauto. intros (q & A & B). subst z.
+ TrivialExists. repeat (econstructor; eauto with evalexpr). exact A.
+Qed.
+
+Theorem eval_shrxlimm:
+ forall le a n x z,
+ eval_expr ge sp e m le a x ->
+ Val.shrxl x (Vint n) = Some z ->
+ exists v, eval_expr ge sp e m le (shrxlimm a n) v /\ Val.lessdef z v.
+Proof.
+ intros; unfold shrxlimm.
+ predSpec Int.eq Int.eq_spec n Int.zero.
+- subst n. exists x; split; auto.
+ destruct x; simpl in H0; try discriminate.
+ change (Int.ltu Int.zero (Int.repr 63)) with true in H0; inv H0.
+ rewrite Int64.shrx'_zero. auto.
+- TrivialExists.
+Qed.
+
+(** General shifts *)
+
+Theorem eval_shll: binary_constructor_sound shll Val.shll.
+Proof.
+ red; intros until y; unfold shll; case (shll_match b); intros.
+ InvEval. apply eval_shllimm; auto.
+ TrivialExists.
+Qed.
+
+Theorem eval_shrl: binary_constructor_sound shrl Val.shrl.
+Proof.
+ red; intros until y; unfold shrl; case (shrl_match b); intros.
+ InvEval. apply eval_shrlimm; auto.
+ TrivialExists.
+Qed.
+
+Theorem eval_shrlu: binary_constructor_sound shrlu Val.shrlu.
+Proof.
+ red; intros until y; unfold shrlu; case (shrlu_match b); intros.
+ InvEval. apply eval_shrluimm; auto.
+ TrivialExists.
+Qed.
+
+(** Comparisons *)
+
+Remark option_map_of_bool_inv: forall ov w,
+ option_map Val.of_bool ov = Some w -> Val.of_optbool ov = w.
+Proof.
+ intros. destruct ov; inv H; auto.
+Qed.
+
+Section COMP_IMM.
+
+Variable default: comparison -> int64 -> condition.
+Variable intsem: comparison -> int64 -> int64 -> bool.
+Variable sem: comparison -> val -> val -> option val.
+
+Hypothesis sem_int: forall c x y,
+ sem c (Vlong x) (Vlong y) = Some (Val.of_bool (intsem c x y)).
+Hypothesis sem_undef: forall c v,
+ sem c Vundef v = None.
+Hypothesis sem_eq: forall x y,
+ sem Ceq (Vlong x) (Vlong y) = Some (Val.of_bool (Int64.eq x y)).
+Hypothesis sem_ne: forall x y,
+ sem Cne (Vlong x) (Vlong y) = Some (Val.of_bool (negb (Int64.eq x y))).
+Hypothesis sem_default: forall c v n,
+ sem c v (Vlong n) = option_map Val.of_bool (eval_condition (default c n) (v :: nil) m).
+
+Lemma eval_complimm_default: forall le a x c n2 v,
+ sem c x (Vlong n2) = Some v ->
+ eval_expr ge sp e m le a x ->
+ eval_expr ge sp e m le (Eop (Ocmp (default c n2)) (a:::Enil)) v.
+Proof.
+ intros. EvalOp. simpl. rewrite sem_default in H. apply option_map_of_bool_inv in H.
+ congruence.
+Qed.
+
+Lemma eval_complimm:
+ forall le c a n2 x v,
+ eval_expr ge sp e m le a x ->
+ sem c x (Vlong n2) = Some v ->
+ eval_expr ge sp e m le (complimm default intsem c a n2) v.
+Proof.
+ intros until x; unfold complimm; case (complimm_match c a); intros; InvEval; subst.
+- (* constant *)
+ rewrite sem_int in H0; inv H0. EvalOp. destruct (intsem c0 n1 n2); auto.
+- (* mask zero *)
+ predSpec Int64.eq Int64.eq_spec n2 Int64.zero.
++ subst n2. destruct v1; simpl in H0; rewrite ? sem_undef, ? sem_eq in H0; inv H0.
+ EvalOp.
++ eapply eval_complimm_default; eauto. EvalOp.
+- (* mask not zero *)
+ predSpec Int64.eq Int64.eq_spec n2 Int64.zero.
++ subst n2. destruct v1; simpl in H0; rewrite ? sem_undef, ? sem_ne in H0; inv H0.
+ EvalOp.
++ eapply eval_complimm_default; eauto. EvalOp.
+- (* default *)
+ eapply eval_complimm_default; eauto.
+Qed.
+
+Hypothesis sem_swap:
+ forall c x y, sem (swap_comparison c) x y = sem c y x.
+
+Lemma eval_complimm_swap:
+ forall le c a n2 x v,
+ eval_expr ge sp e m le a x ->
+ sem c (Vlong n2) x = Some v ->
+ eval_expr ge sp e m le (complimm default intsem (swap_comparison c) a n2) v.
+Proof.
+ intros. eapply eval_complimm; eauto. rewrite sem_swap; auto.
+Qed.
+
+End COMP_IMM.
+
+Theorem eval_cmpl:
+ forall c le a x b y v,
+ eval_expr ge sp e m le a x ->
+ eval_expr ge sp e m le b y ->
+ Val.cmpl c x y = Some v ->
+ eval_expr ge sp e m le (cmpl c a b) v.
+Proof.
+ intros until y; unfold cmpl; case (cmpl_match a b); intros; InvEval; subst.
+- apply eval_complimm_swap with (sem := Val.cmpl) (x := y); auto.
+ intros; unfold Val.cmpl; rewrite Val.swap_cmpl_bool; auto.
+- apply eval_complimm with (sem := Val.cmpl) (x := x); auto.
+- EvalOp. simpl. rewrite Val.swap_cmpl_bool. apply option_map_of_bool_inv in H1. congruence.
+- EvalOp. simpl. apply option_map_of_bool_inv in H1. congruence.
+- EvalOp. simpl. apply option_map_of_bool_inv in H1. congruence.
+Qed.
+
+Theorem eval_cmplu:
+ forall c le a x b y v,
+ eval_expr ge sp e m le a x ->
+ eval_expr ge sp e m le b y ->
+ Val.cmplu (Mem.valid_pointer m) c x y = Some v ->
+ eval_expr ge sp e m le (cmplu c a b) v.
+Proof.
+ intros until y; unfold cmplu; case (cmplu_match a b); intros; InvEval; subst.
+- apply eval_complimm_swap with (sem := Val.cmplu (Mem.valid_pointer m)) (x := y); auto.
+ intros; unfold Val.cmplu; rewrite Val.swap_cmplu_bool; auto.
+- apply eval_complimm with (sem := Val.cmplu (Mem.valid_pointer m)) (x := x); auto.
+- EvalOp. simpl. rewrite Val.swap_cmplu_bool. apply option_map_of_bool_inv in H1. congruence.
+- EvalOp. simpl. apply option_map_of_bool_inv in H1. congruence.
+- EvalOp. simpl. apply option_map_of_bool_inv in H1. congruence.
+Qed.
+
+
+(** Floating-point conversions *)
+
+Theorem eval_longoffloat: partial_unary_constructor_sound longoffloat Val.longoffloat.
+Proof.
+ red; intros; TrivialExists.
+Qed.
+
+Theorem eval_longuoffloat: partial_unary_constructor_sound longuoffloat Val.longuoffloat.
+Proof.
+ red; intros; TrivialExists.
+Qed.
+
+Theorem eval_floatoflong: partial_unary_constructor_sound floatoflong Val.floatoflong.
+Proof.
+ red; intros; TrivialExists.
+Qed.
+
+Theorem eval_floatoflongu: partial_unary_constructor_sound floatoflongu Val.floatoflongu.
+Proof.
+ red; intros; TrivialExists.
+Qed.
+
+Theorem eval_longofsingle: partial_unary_constructor_sound longofsingle Val.longofsingle.
+Proof.
+ red; intros; TrivialExists.
+Qed.
+
+Theorem eval_longuofsingle: partial_unary_constructor_sound longuofsingle Val.longuofsingle.
+Proof.
+ red; intros; TrivialExists.
+Qed.
+
+Theorem eval_singleoflong: partial_unary_constructor_sound singleoflong Val.singleoflong.
+Proof.
+ red; intros; TrivialExists.
+Qed.
+
+Theorem eval_singleoflongu: partial_unary_constructor_sound singleoflongu Val.singleoflongu.
+Proof.
+ red; intros; TrivialExists.
+Qed.
+
+End CMCONSTR.
diff --git a/aarch64/SelectOp.vp b/aarch64/SelectOp.vp
new file mode 100644
index 00000000..5bd96987
--- /dev/null
+++ b/aarch64/SelectOp.vp
@@ -0,0 +1,566 @@
+(* *********************************************************************)
+(* *)
+(* 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. *)
+(* *)
+(* *********************************************************************)
+
+(** Instruction selection for operators *)
+
+Require Import Coqlib Zbits.
+Require Import Compopts AST Integers Floats Builtins.
+Require Import Op CminorSel.
+
+Local Open Scope cminorsel_scope.
+
+(** "ror" shifted operands are not supported by arithmetic operations *)
+
+Definition arith_shift (s: shift) :=
+ match s with Sror => false | _ => true end.
+
+(** ** Constants **)
+
+Definition addrsymbol (id: ident) (ofs: ptrofs) :=
+ Eop (Oaddrsymbol id ofs) Enil.
+
+Definition addrstack (ofs: ptrofs) :=
+ Eop (Oaddrstack ofs) Enil.
+
+(** ** Integer addition *)
+
+Nondetfunction addimm (n: int) (e: expr) :=
+ if Int.eq n Int.zero then e else
+ match e with
+ | Eop (Ointconst m) Enil => Eop (Ointconst (Int.add n m)) Enil
+ | Eop (Oaddimm m) (t ::: Enil) => Eop (Oaddimm(Int.add n m)) (t ::: Enil)
+ | _ => Eop (Oaddimm n) (e ::: Enil)
+ end.
+
+Nondetfunction add (e1: expr) (e2: expr) :=
+ match e1, e2 with
+ | Eop (Ointconst n1) Enil, t2 => addimm n1 t2
+ | t1, Eop (Ointconst n2) Enil => addimm n2 t1
+ | Eop (Oaddimm n1) (t1:::Enil), Eop (Oaddimm n2) (t2:::Enil) =>
+ addimm (Int.add n1 n2) (Eop Oadd (t1:::t2:::Enil))
+ | Eop (Oaddimm n1) (t1:::Enil), t2 =>
+ addimm n1 (Eop Oadd (t1:::t2:::Enil))
+ | t1, Eop (Oaddimm n2) (t2:::Enil) =>
+ addimm n2 (Eop Oadd (t1:::t2:::Enil))
+ | Eop (Oshift s a) (t1:::Enil), t2 ?? arith_shift s =>
+ Eop (Oaddshift s a) (t2 ::: t1 ::: Enil)
+ | t1, Eop (Oshift s a) (t2:::Enil) ?? arith_shift s =>
+ Eop (Oaddshift s a) (t1 ::: t2 ::: Enil)
+ | Eop Omul (t1:::t2:::Enil), t3 =>
+ Eop Omuladd (t3:::t1:::t2:::Enil)
+ | t1, Eop Omul (t2:::t3:::Enil) =>
+ Eop Omuladd (t1:::t2:::t3:::Enil)
+ | _, _ => Eop Oadd (e1:::e2:::Enil)
+ end.
+
+(** ** Opposite *)
+
+Nondetfunction negint (e: expr) :=
+ match e with
+ | Eop (Ointconst n) Enil => Eop (Ointconst (Int.neg n)) Enil
+ | Eop (Oshift s a) (t1:::Enil) ?? arith_shift s => Eop (Onegshift s a) (t1:::Enil)
+ | _ => Eop Oneg (e ::: Enil)
+ end.
+
+(** ** Integer and pointer subtraction *)
+
+Nondetfunction sub (e1: expr) (e2: expr) :=
+ match e1, e2 with
+ | t1, Eop (Ointconst n2) Enil =>
+ addimm (Int.neg n2) t1
+ | Eop (Oaddimm n1) (t1:::Enil), Eop (Oaddimm n2) (t2:::Enil) =>
+ addimm (Int.sub n1 n2) (Eop Osub (t1:::t2:::Enil))
+ | Eop (Oaddimm n1) (t1:::Enil), t2 =>
+ addimm n1 (Eop Osub (t1:::t2:::Enil))
+ | t1, Eop (Oaddimm n2) (t2:::Enil) =>
+ addimm (Int.neg n2) (Eop Osub (t1:::t2:::Enil))
+ | t1, Eop (Oshift s a) (t2:::Enil) ?? arith_shift s =>
+ Eop (Osubshift s a) (t1:::t2::: Enil)
+ | t1, Eop Omul (t2:::t3:::Enil) =>
+ Eop Omulsub (t1:::t2:::t3:::Enil)
+ | _, _ => Eop Osub (e1:::e2:::Enil)
+ end.
+
+(** ** Immediate shift left *)
+
+Definition shlimm_base (e1: expr) (n: int) :=
+ Eop (Oshift Slsl (mk_amount32 n)) (e1 ::: Enil).
+
+Nondetfunction shlimm (e1: expr) (n: int) :=
+ if Int.eq n Int.zero then
+ e1
+ else if negb (Int.ltu n Int.iwordsize) then
+ Eop Oshl (e1 ::: Eop (Ointconst n) Enil ::: Enil)
+ else match e1 with
+ | Eop (Ointconst n1) Enil =>
+ Eop (Ointconst (Int.shl n1 n)) Enil
+ | Eop (Oshift Slsl a) (t1:::Enil) =>
+ if Int.ltu (Int.add a n) Int.iwordsize
+ then shlimm_base t1 (Int.add a n)
+ else shlimm_base e1 n
+ | Eop (Ozext s) (t1:::Enil) =>
+ Eop (Oshlzext s (mk_amount32 n)) (t1:::Enil)
+ | Eop (Osext s) (t1:::Enil) =>
+ Eop (Oshlsext s (mk_amount32 n)) (t1:::Enil)
+ | Eop (Oshlzext s a) (t1:::Enil) =>
+ if Int.ltu (Int.add a n) Int.iwordsize
+ then Eop (Oshlzext s (mk_amount32 (Int.add a n))) (t1:::Enil)
+ else shlimm_base e1 n
+ | Eop (Oshlsext s a) (t1:::Enil) =>
+ if Int.ltu (Int.add a n) Int.iwordsize
+ then Eop (Oshlsext s (mk_amount32 (Int.add a n))) (t1:::Enil)
+ else shlimm_base e1 n
+ | _ =>
+ shlimm_base e1 n
+ end.
+
+(** ** Immediate shift right (logical) *)
+
+Definition shruimm_base (e1: expr) (n: int) :=
+ Eop (Oshift Slsr (mk_amount32 n)) (e1 ::: Enil).
+
+Nondetfunction shruimm (e1: expr) (n: int) :=
+ if Int.eq n Int.zero then
+ e1
+ else if negb (Int.ltu n Int.iwordsize) then
+ Eop Oshru (e1 ::: Eop (Ointconst n) Enil ::: Enil)
+ else match e1 with
+ | Eop (Ointconst n1) Enil =>
+ Eop (Ointconst (Int.shru n1 n)) Enil
+ | Eop (Oshift Slsl a) (t1:::Enil) =>
+ if Int.ltu n a
+ then Eop (Oshlzext (Int.zwordsize - Int.unsigned a) (mk_amount32 (Int.sub a n))) (t1:::Enil)
+ else Eop (Ozextshr (mk_amount32 (Int.sub n a)) (Int.zwordsize - Int.unsigned n)) (t1:::Enil)
+ | Eop (Oshift Slsr a) (t1:::Enil) =>
+ if Int.ltu (Int.add a n) Int.iwordsize
+ then shruimm_base t1 (Int.add a n)
+ else shruimm_base e1 n
+ | Eop (Ozext s) (t1:::Enil) =>
+ if zlt (Int.unsigned n) s
+ then Eop (Ozextshr (mk_amount32 n) (s - Int.unsigned n)) (t1:::Enil)
+ else Eop (Ointconst Int.zero) Enil
+ | _ =>
+ shruimm_base e1 n
+ end.
+
+(** ** Immediate shift right (arithmetic) *)
+
+Definition shrimm_base (e1: expr) (n: int) :=
+ Eop (Oshift Sasr (mk_amount32 n)) (e1 ::: Enil).
+
+Nondetfunction shrimm (e1: expr) (n: int) :=
+ if Int.eq n Int.zero then
+ e1
+ else if negb (Int.ltu n Int.iwordsize) then
+ Eop Oshr (e1 ::: Eop (Ointconst n) Enil ::: Enil)
+ else match e1 with
+ | Eop (Ointconst n1) Enil =>
+ Eop (Ointconst (Int.shr n1 n)) Enil
+ | Eop (Oshift Slsl a) (t1:::Enil) =>
+ if Int.ltu n a
+ then Eop (Oshlsext (Int.zwordsize - Int.unsigned a) (mk_amount32 (Int.sub a n))) (t1:::Enil)
+ else Eop (Osextshr (mk_amount32 (Int.sub n a)) (Int.zwordsize - Int.unsigned n)) (t1:::Enil)
+ | Eop (Oshift Sasr a) (t1:::Enil) =>
+ if Int.ltu (Int.add a n) Int.iwordsize
+ then shrimm_base t1 (Int.add a n)
+ else shrimm_base e1 n
+ | Eop (Osext s) (t1:::Enil) =>
+ if zlt (Int.unsigned n) s && zlt s Int.zwordsize
+ then Eop (Osextshr (mk_amount32 n) (s - Int.unsigned n)) (t1:::Enil)
+ else shrimm_base e1 n
+ | _ =>
+ shrimm_base e1 n
+ end.
+
+(** ** Integer multiply *)
+
+Definition mulimm_base (n1: int) (e2: expr) :=
+ match Int.one_bits n1 with
+ | i :: nil =>
+ shlimm e2 i
+ | i :: j :: nil =>
+ Elet e2 (add (shlimm (Eletvar 0) i) (shlimm (Eletvar 0) j))
+ | _ =>
+ Eop Omul (Eop (Ointconst n1) Enil ::: e2 ::: Enil)
+ end.
+
+Nondetfunction mulimm (n1: int) (e2: expr) :=
+ if Int.eq n1 Int.zero then Eop (Ointconst Int.zero) Enil
+ else if Int.eq n1 Int.one then e2
+ else match e2 with
+ | Eop (Ointconst n2) Enil => Eop (Ointconst (Int.mul n1 n2)) Enil
+ | Eop (Oaddimm n2) (t2:::Enil) => addimm (Int.mul n1 n2) (mulimm_base n1 t2)
+ | _ => mulimm_base n1 e2
+ end.
+
+Nondetfunction mul (e1: expr) (e2: expr) :=
+ match e1, e2 with
+ | Eop (Ointconst n1) Enil, t2 => mulimm n1 t2
+ | t1, Eop (Ointconst n2) Enil => mulimm n2 t1
+ | _, _ => Eop Omul (e1:::e2:::Enil)
+ end.
+
+Definition mulhs (e1: expr) (e2: expr) :=
+ Eop Olowlong
+ (Eop (Oshiftl Sasr (mk_amount64 (Int.repr 32)))
+ (Eop Omull (Eop (Oextend Xsgn32 (mk_amount64 Int.zero)) (e1 ::: Enil) :::
+ Eop (Oextend Xsgn32 (mk_amount64 Int.zero)) (e2 ::: Enil) ::: Enil) ::: Enil)
+ ::: Enil).
+
+Definition mulhu (e1: expr) (e2: expr) :=
+ Eop Olowlong
+ (Eop (Oshiftl Slsr (mk_amount64 (Int.repr 32)))
+ (Eop Omull (Eop (Oextend Xuns32 (mk_amount64 Int.zero)) (e1 ::: Enil) :::
+ Eop (Oextend Xuns32 (mk_amount64 Int.zero)) (e2 ::: Enil) ::: Enil) ::: Enil)
+ ::: Enil).
+
+(** ** Integer conversions *)
+
+Nondetfunction zero_ext (sz: Z) (e: expr) :=
+ match e with
+ | Eop (Ointconst n) Enil => Eop (Ointconst (Int.zero_ext sz n)) Enil
+ | Eop (Oshift Slsr a) (t1:::Enil) => Eop (Ozextshr a sz) (t1:::Enil)
+ | Eop (Oshift Slsl a) (t1:::Enil) =>
+ if zlt (Int.unsigned a) sz
+ then Eop (Oshlzext (sz - Int.unsigned a) a) (t1:::Enil)
+ else Eop (Ozext sz) (e:::Enil)
+ | _ => Eop (Ozext sz) (e:::Enil)
+ end.
+
+Nondetfunction sign_ext (sz: Z) (e: expr) :=
+ match e with
+ | Eop (Ointconst n) Enil => Eop (Ointconst (Int.sign_ext sz n)) Enil
+ | Eop (Oshift Sasr a) (t1:::Enil) => Eop (Osextshr a sz) (t1:::Enil)
+ | Eop (Oshift Slsl a) (t1:::Enil) =>
+ if zlt (Int.unsigned a) sz
+ then Eop (Oshlsext (sz - Int.unsigned a) a) (t1:::Enil)
+ else Eop (Osext sz) (e:::Enil)
+ | _ => Eop (Osext sz) (e:::Enil)
+ end.
+
+Definition cast8unsigned (e: expr) := zero_ext 8 e.
+Definition cast8signed (e: expr) := sign_ext 8 e.
+Definition cast16unsigned (e: expr) := zero_ext 16 e.
+Definition cast16signed (e: expr) := sign_ext 16 e.
+
+(** ** Bitwise not *)
+
+Nondetfunction notint (e: expr) :=
+ match e with
+ | Eop (Ointconst n) Enil => Eop (Ointconst (Int.not n)) Enil
+ | Eop (Oshift s a) (t1:::Enil) => Eop (Onotshift s a) (t1:::Enil)
+ | Eop Onot (t1:::Enil) => t1
+ | Eop (Onotshift s a) (t1:::Enil) => Eop (Oshift s a) (t1:::Enil)
+ | Eop Obic (t1:::t2:::Enil) => Eop Oorn (t2:::t1:::Enil)
+ | Eop Oorn (t1:::t2:::Enil) => Eop Obic (t2:::t1:::Enil)
+ | Eop Oxor (t1:::t2:::Enil) => Eop Oeqv (t1:::t2:::Enil)
+ | Eop Oeqv (t1:::t2:::Enil) => Eop Oxor (t1:::t2:::Enil)
+ | _ => Eop Onot (e:::Enil)
+ end.
+
+(** ** Bitwise and *)
+
+Definition andimm_base (n1: int) (e2: expr) :=
+ if Int.eq n1 Int.zero then Eop (Ointconst Int.zero) Enil else
+ if Int.eq n1 Int.mone then e2 else
+ match Z_is_power2m1 (Int.unsigned n1) with
+ | Some s => zero_ext s e2
+ | None => Eop (Oandimm n1) (e2 ::: Enil)
+ end.
+
+Nondetfunction andimm (n1: int) (e2: expr) :=
+ match e2 with
+ | Eop (Ointconst n2) Enil => Eop (Ointconst (Int.and n1 n2)) Enil
+ | Eop (Oandimm n2) (t2:::Enil) => andimm_base (Int.and n1 n2) t2
+ | Eop (Ozext s) (t2:::Enil) =>
+ if zle 0 s
+ then andimm_base (Int.and n1 (Int.repr (two_p s - 1))) t2
+ else andimm_base n1 e2
+ | _ => andimm_base n1 e2
+ end.
+
+Nondetfunction and (e1: expr) (e2: expr) :=
+ match e1, e2 with
+ | Eop (Ointconst n1) Enil, t2 => andimm n1 t2
+ | t1, Eop (Ointconst n2) Enil => andimm n2 t1
+ | Eop Onot (t1:::Enil), t2 => Eop Obic (t2:::t1:::Enil)
+ | t1, Eop Onot (t2:::Enil) => Eop Obic (t1:::t2:::Enil)
+ | Eop (Onotshift s a) (t1:::Enil), t2 => Eop (Obicshift s a) (t2:::t1:::Enil)
+ | t1, Eop (Onotshift s a) (t2:::Enil) => Eop (Obicshift s a) (t1:::t2:::Enil)
+ | Eop (Oshift s a) (t1:::Enil), t2 => Eop (Oandshift s a) (t2:::t1:::Enil)
+ | t1, Eop (Oshift s a) (t2:::Enil) => Eop (Oandshift s a) (t1:::t2:::Enil)
+ | _, _ => Eop Oand (e1:::e2:::Enil)
+ end.
+
+(** ** Bitwise or *)
+
+Nondetfunction orimm (n1: int) (e2: expr) :=
+ if Int.eq n1 Int.zero then e2
+ else if Int.eq n1 Int.mone then Eop (Ointconst Int.mone) Enil
+ else match e2 with
+ | Eop (Ointconst n2) Enil => Eop (Ointconst (Int.or n1 n2)) Enil
+ | Eop (Oorimm n2) (t2:::Enil) => Eop (Oorimm (Int.or n1 n2)) (t2:::Enil)
+ | _ => Eop (Oorimm n1) (e2:::Enil)
+ end.
+
+Definition same_expr_pure (e1 e2: expr) :=
+ match e1, e2 with
+ | Evar v1, Evar v2 => if ident_eq v1 v2 then true else false
+ | _, _ => false
+ end.
+
+Nondetfunction or (e1: expr) (e2: expr) :=
+ match e1, e2 with
+ | Eop (Ointconst n1) Enil, t2 => orimm n1 t2
+ | t1, Eop (Ointconst n2) Enil => orimm n2 t1
+ | Eop Onot (t1:::Enil), t2 => Eop Oorn (t2:::t1:::Enil)
+ | t1, Eop Onot (t2:::Enil) => Eop Oorn (t1:::t2:::Enil)
+ | Eop (Onotshift s a) (t1:::Enil), t2 => Eop (Oornshift s a) (t2:::t1:::Enil)
+ | t1, Eop (Onotshift s a) (t2:::Enil) => Eop (Oornshift s a) (t1:::t2:::Enil)
+ | Eop (Oshift Slsl a1) (t1:::Enil), Eop (Oshift Slsr a2) (t2:::Enil) =>
+ if Int.eq (Int.add a1 a2) Int.iwordsize && same_expr_pure t1 t2
+ then Eop (Oshift Sror a2) (t2:::Enil)
+ else Eop (Oorshift Slsr a2) (Eop (Oshift Slsl a1) (t1:::Enil):::t2:::Enil)
+ | Eop (Oshift Slsr a1) (t1:::Enil), Eop (Oshift Slsl a2) (t2:::Enil) =>
+ if Int.eq (Int.add a2 a1) Int.iwordsize && same_expr_pure t1 t2
+ then Eop (Oshift Sror a1) (t1:::Enil)
+ else Eop (Oorshift Slsl a2) (Eop (Oshift Slsr a1) (t1:::Enil):::t2:::Enil)
+ | Eop (Oshift s a) (t1:::Enil), t2 => Eop (Oorshift s a) (t2:::t1:::Enil)
+ | t1, Eop (Oshift s a) (t2:::Enil) => Eop (Oorshift s a) (t1:::t2:::Enil)
+ | _, _ => Eop Oor (e1:::e2:::Enil)
+ end.
+
+(** ** Bitwise xor *)
+
+Definition xorimm_base (n1: int) (e2: expr) :=
+ if Int.eq n1 Int.zero then e2 else
+ if Int.eq n1 Int.mone then notint e2 else
+ Eop (Oxorimm n1) (e2:::Enil).
+
+Nondetfunction xorimm (n1: int) (e2: expr) :=
+ match e2 with
+ | Eop (Ointconst n2) Enil => Eop (Ointconst (Int.xor n1 n2)) Enil
+ | Eop (Oxorimm n2) (t2:::Enil) => xorimm_base (Int.xor n1 n2) t2
+ | _ => xorimm_base n1 e2
+ end.
+
+Nondetfunction xor (e1: expr) (e2: expr) :=
+ match e1, e2 with
+ | Eop (Ointconst n1) Enil, t2 => xorimm n1 t2
+ | t1, Eop (Ointconst n2) Enil => xorimm n2 t1
+ | Eop Onot (t1:::Enil), t2 => Eop Oeqv (t2:::t1:::Enil)
+ | t1, Eop Onot (t2:::Enil) => Eop Oeqv (t1:::t2:::Enil)
+ | Eop (Onotshift s a) (t1:::Enil), t2 => Eop (Oeqvshift s a) (t2:::t1:::Enil)
+ | t1, Eop (Onotshift s a) (t2:::Enil) => Eop (Oeqvshift s a) (t1:::t2:::Enil)
+ | Eop (Oshift s a) (t1:::Enil), t2 => Eop (Oxorshift s a) (t2:::t1:::Enil)
+ | t1, Eop (Oshift s a) (t2:::Enil) => Eop (Oxorshift s a) (t1:::t2:::Enil)
+ | _, _ => Eop Oxor (e1:::e2:::Enil)
+ end.
+
+(** ** Integer division and modulus *)
+
+Definition mod_aux (divop: operation) (e1 e2: expr) :=
+ Elet e1
+ (Elet (lift e2)
+ (Eop Omulsub (Eletvar 1 :::
+ Eop divop (Eletvar 1 ::: Eletvar 0 ::: Enil) :::
+ Eletvar 0 :::
+ Enil))).
+
+Definition divs_base (e1: expr) (e2: expr) := Eop Odiv (e1:::e2:::Enil).
+Definition mods_base := mod_aux Odiv.
+Definition divu_base (e1: expr) (e2: expr) := Eop Odivu (e1:::e2:::Enil).
+Definition modu_base := mod_aux Odivu.
+
+Definition shrximm (e1: expr) (n2: int) :=
+ if Int.eq n2 Int.zero then e1 else Eop (Oshrximm n2) (e1:::Enil).
+
+(** ** General shifts *)
+
+Nondetfunction shl (e1: expr) (e2: expr) :=
+ match e2 with
+ | Eop (Ointconst n2) Enil => shlimm e1 n2
+ | _ => Eop Oshl (e1:::e2:::Enil)
+ end.
+
+Nondetfunction shr (e1: expr) (e2: expr) :=
+ match e2 with
+ | Eop (Ointconst n2) Enil => shrimm e1 n2
+ | _ => Eop Oshr (e1:::e2:::Enil)
+ end.
+
+Nondetfunction shru (e1: expr) (e2: expr) :=
+ match e2 with
+ | Eop (Ointconst n2) Enil => shruimm e1 n2
+ | _ => Eop Oshru (e1:::e2:::Enil)
+ end.
+
+(** ** Floating-point arithmetic *)
+
+Definition negf (e: expr) := Eop Onegf (e ::: Enil).
+Definition absf (e: expr) := Eop Oabsf (e ::: Enil).
+Definition addf (e1 e2: expr) := Eop Oaddf (e1 ::: e2 ::: Enil).
+Definition subf (e1 e2: expr) := Eop Osubf (e1 ::: e2 ::: Enil).
+Definition mulf (e1 e2: expr) := Eop Omulf (e1 ::: e2 ::: Enil).
+
+Definition negfs (e: expr) := Eop Onegfs (e ::: Enil).
+Definition absfs (e: expr) := Eop Oabsfs (e ::: Enil).
+Definition addfs (e1 e2: expr) := Eop Oaddfs (e1 ::: e2 ::: Enil).
+Definition subfs (e1 e2: expr) := Eop Osubfs (e1 ::: e2 ::: Enil).
+Definition mulfs (e1 e2: expr) := Eop Omulfs (e1 ::: e2 ::: Enil).
+
+(** ** Comparisons *)
+
+Nondetfunction compimm (default: comparison -> int -> condition)
+ (sem: comparison -> int -> int -> bool)
+ (c: comparison) (e1: expr) (n2: int) :=
+ match c, e1 with
+ | c, Eop (Ointconst n1) Enil =>
+ Eop (Ointconst (if sem c n1 n2 then Int.one else Int.zero)) Enil
+ | Ceq, Eop (Ocmp c) el =>
+ if Int.eq_dec n2 Int.zero then
+ Eop (Ocmp (negate_condition c)) el
+ else if Int.eq_dec n2 Int.one then
+ Eop (Ocmp c) el
+ else
+ Eop (Ointconst Int.zero) Enil
+ | Cne, Eop (Ocmp c) el =>
+ if Int.eq_dec n2 Int.zero then
+ Eop (Ocmp c) el
+ else if Int.eq_dec n2 Int.one then
+ Eop (Ocmp (negate_condition c)) el
+ else
+ Eop (Ointconst Int.one) Enil
+ | Ceq, Eop (Oandimm m) (t1:::Enil) =>
+ if Int.eq n2 Int.zero
+ then Eop (Ocmp (Cmaskzero m)) (t1:::Enil)
+ else Eop (Ocmp (default c n2)) (e1:::Enil)
+ | Cne, Eop (Oandimm m) (t1:::Enil) =>
+ if Int.eq n2 Int.zero
+ then Eop (Ocmp (Cmasknotzero m)) (t1:::Enil)
+ else Eop (Ocmp (default c n2)) (e1:::Enil)
+ | _, _ =>
+ Eop (Ocmp (default c n2)) (e1:::Enil)
+ end.
+
+Nondetfunction comp (c: comparison) (e1: expr) (e2: expr) :=
+ match e1, e2 with
+ | Eop (Ointconst n1) Enil, t2 =>
+ compimm Ccompimm Int.cmp (swap_comparison c) t2 n1
+ | t1, Eop (Ointconst n2) Enil =>
+ compimm Ccompimm Int.cmp c t1 n2
+ | Eop (Oshift s a) (t1:::Enil), t2 ?? arith_shift s =>
+ Eop (Ocmp (Ccompshift (swap_comparison c) s a)) (t2:::t1:::Enil)
+ | t1, Eop (Oshift s a) (t2:::Enil) ?? arith_shift s =>
+ Eop (Ocmp (Ccompshift c s a)) (t1:::t2:::Enil)
+ | _, _ =>
+ Eop (Ocmp (Ccomp c)) (e1:::e2:::Enil)
+ end.
+
+Nondetfunction compu (c: comparison) (e1: expr) (e2: expr) :=
+ match e1, e2 with
+ | Eop (Ointconst n1) Enil, t2 =>
+ compimm Ccompuimm Int.cmpu (swap_comparison c) t2 n1
+ | t1, Eop (Ointconst n2) Enil =>
+ compimm Ccompuimm Int.cmpu c t1 n2
+ | Eop (Oshift s a) (t1:::Enil), t2 ?? arith_shift s =>
+ Eop (Ocmp (Ccompushift (swap_comparison c) s a)) (t2:::t1:::Enil)
+ | t1, Eop (Oshift s a) (t2:::Enil) ?? arith_shift s =>
+ Eop (Ocmp (Ccompushift c s a)) (t1:::t2:::Enil)
+ | _, _ =>
+ Eop (Ocmp (Ccompu c)) (e1:::e2:::Enil)
+ end.
+
+Definition compf (c: comparison) (e1: expr) (e2: expr) :=
+ Eop (Ocmp (Ccompf c)) (e1:::e2:::Enil).
+
+Definition compfs (c: comparison) (e1: expr) (e2: expr) :=
+ Eop (Ocmp (Ccompfs c)) (e1:::e2:::Enil).
+
+(** ** Floating-point conversions *)
+
+Definition intoffloat (e: expr) := Eop Ointoffloat (e ::: Enil).
+Definition intuoffloat (e: expr) := Eop Ointuoffloat (e ::: Enil).
+
+Nondetfunction floatofintu (e: expr) :=
+ match e with
+ | Eop (Ointconst n) Enil => Eop (Ofloatconst (Float.of_intu n)) Enil
+ | _ => Eop Ofloatofintu (e ::: Enil)
+ end.
+
+Nondetfunction floatofint (e: expr) :=
+ match e with
+ | Eop (Ointconst n) Enil => Eop (Ofloatconst (Float.of_int n)) Enil
+ | _ => Eop Ofloatofint (e ::: Enil)
+ end.
+
+Definition intofsingle (e: expr) := Eop Ointofsingle (e ::: Enil).
+Definition intuofsingle (e: expr) := Eop Ointuofsingle (e ::: Enil).
+
+Nondetfunction singleofint (e: expr) :=
+ match e with
+ | Eop (Ointconst n) Enil => Eop (Osingleconst (Float32.of_int n)) Enil
+ | _ => Eop Osingleofint (e ::: Enil)
+ end.
+
+Nondetfunction singleofintu (e: expr) :=
+ match e with
+ | Eop (Ointconst n) Enil => Eop (Osingleconst (Float32.of_intu n)) Enil
+ | _ => Eop Osingleofintu (e ::: Enil)
+ end.
+
+Definition singleoffloat (e: expr) := Eop Osingleoffloat (e ::: Enil).
+Definition floatofsingle (e: expr) := Eop Ofloatofsingle (e ::: Enil).
+
+(** ** Selection *)
+
+Definition select (ty: typ) (cond: condition) (args: exprlist) (e1 e2: expr) :=
+ if match ty with
+ | Tint => true
+ | Tlong => true
+ | Tfloat => true
+ | Tsingle => true
+ | _ => false
+ end
+ then Some (Eop (Osel cond ty) (e1 ::: e2 ::: args))
+ else None.
+
+(** ** Recognition of addressing modes for load and store operations *)
+
+Nondetfunction addressing (chunk: memory_chunk) (e: expr) :=
+ match e with
+ | Eop (Oaddrstack n) Enil => (Ainstack n, Enil)
+ | Eop (Oaddrsymbol id ofs) Enil => (Aglobal id ofs, Enil)
+ | Eop (Oaddlimm n) (e1:::Enil) => (Aindexed n, e1:::Enil)
+ | Eop (Oaddlshift Slsl a) (e1:::e2:::Enil) => (Aindexed2shift a, e1:::e2:::Enil)
+ | Eop (Oaddlext x a) (e1:::e2:::Enil) => (Aindexed2ext x a, e1:::e2:::Enil)
+ | Eop Oaddl (e1:::e2:::Enil) => (Aindexed2, e1:::e2:::Enil)
+ | _ => (Aindexed Int64.zero, e:::Enil)
+ end.
+
+(** ** Arguments of builtins *)
+
+Nondetfunction builtin_arg (e: expr) :=
+ match e with
+ | Eop (Ointconst n) Enil => BA_int n
+ | Eop (Olongconst n) Enil => BA_long n
+ | Eop (Oaddrsymbol id ofs) Enil => BA_addrglobal id ofs
+ | Eop (Oaddrstack ofs) Enil => BA_addrstack ofs
+ | Eload chunk (Ainstack ofs) Enil => BA_loadstack chunk ofs
+ | Eop (Oaddlimm n) (e1:::Enil) => BA_addptr (BA e1) (BA_long n)
+ | _ => BA e
+ end.
+
+(** Platform-specific known builtins *)
+
+Definition platform_builtin (b: platform_builtin) (args: exprlist) : option expr :=
+ None.
diff --git a/aarch64/SelectOpproof.v b/aarch64/SelectOpproof.v
new file mode 100644
index 00000000..b78a5ed8
--- /dev/null
+++ b/aarch64/SelectOpproof.v
@@ -0,0 +1,1070 @@
+(* *********************************************************************)
+(* *)
+(* 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 of instruction selection for operators *)
+
+Require Import Coqlib Zbits.
+Require Import AST Integers Floats Values Memory Builtins Globalenvs.
+Require Import Cminor Op CminorSel.
+Require Import SelectOp.
+
+Local Open Scope cminorsel_scope.
+Local Transparent Archi.ptr64.
+
+(** * Useful lemmas and tactics *)
+
+(** The following are trivial lemmas and custom tactics that help
+ perform backward (inversion) and forward reasoning over the evaluation
+ of operator applications. *)
+
+Ltac EvalOp :=
+ eauto with evalexpr;
+ match goal with
+ | [ |- eval_expr _ _ _ _ _ _ _ ] => eapply eval_Eop; [EvalOp|try reflexivity; auto]
+ | [ |- eval_exprlist _ _ _ _ _ _ _ ] => econstructor; EvalOp
+ | _ => idtac
+ end.
+
+Ltac InvEval1 :=
+ match goal with
+ | [ H: (eval_expr _ _ _ _ _ (Eop _ Enil) _) |- _ ] =>
+ inv H; InvEval1
+ | [ H: (eval_expr _ _ _ _ _ (Eop _ (_ ::: Enil)) _) |- _ ] =>
+ inv H; InvEval1
+ | [ H: (eval_expr _ _ _ _ _ (Eop _ (_ ::: _ ::: Enil)) _) |- _ ] =>
+ inv H; InvEval1
+ | [ H: (eval_exprlist _ _ _ _ _ Enil _) |- _ ] =>
+ inv H; InvEval1
+ | [ H: (eval_exprlist _ _ _ _ _ (_ ::: _) _) |- _ ] =>
+ inv H; InvEval1
+ | _ =>
+ idtac
+ end.
+
+Ltac InvEval2 :=
+ match goal with
+ | [ H: (eval_operation _ _ _ nil _ = Some _) |- _ ] =>
+ simpl in H; inv H
+ | [ H: (eval_operation _ _ _ (_ :: nil) _ = Some _) |- _ ] =>
+ simpl in H; FuncInv
+ | [ H: (eval_operation _ _ _ (_ :: _ :: nil) _ = Some _) |- _ ] =>
+ simpl in H; FuncInv
+ | [ H: (eval_operation _ _ _ (_ :: _ :: _ :: nil) _ = Some _) |- _ ] =>
+ simpl in H; FuncInv
+ | _ =>
+ idtac
+ end.
+
+Ltac InvEval := InvEval1; InvEval2; InvEval2.
+
+Ltac TrivialExists :=
+ match goal with
+ | [ |- exists v, _ /\ Val.lessdef ?a v ] => exists a; split; [EvalOp | auto]
+ end.
+
+(** * Correctness of the smart constructors *)
+
+Section CMCONSTR.
+
+Variable ge: genv.
+Variable sp: val.
+Variable e: env.
+Variable m: mem.
+
+(** We now show that the code generated by "smart constructor" functions
+ such as [Selection.notint] behaves as expected. Continuing the
+ [notint] example, we show that if the expression [e]
+ evaluates to some integer value [Vint n], then [Selection.notint e]
+ evaluates to a value [Vint (Int.not n)] which is indeed the integer
+ negation of the value of [e].
+
+ All proofs follow a common pattern:
+- Reasoning by case over the result of the classification functions
+ (such as [add_match] for integer addition), gathering additional
+ information on the shape of the argument expressions in the non-default
+ cases.
+- Inversion of the evaluations of the arguments, exploiting the additional
+ information thus gathered.
+- Equational reasoning over the arithmetic operations performed,
+ using the lemmas from the [Int] and [Float] modules.
+- Construction of an evaluation derivation for the expression returned
+ by the smart constructor.
+*)
+
+Definition unary_constructor_sound (cstr: expr -> expr) (sem: val -> val) : Prop :=
+ forall le a x,
+ eval_expr ge sp e m le a x ->
+ exists v, eval_expr ge sp e m le (cstr a) v /\ Val.lessdef (sem x) v.
+
+Definition binary_constructor_sound (cstr: expr -> expr -> expr) (sem: val -> val -> val) : Prop :=
+ forall le a x b y,
+ eval_expr ge sp e m le a x ->
+ eval_expr ge sp e m le b y ->
+ exists v, eval_expr ge sp e m le (cstr a b) v /\ Val.lessdef (sem x y) v.
+
+(** ** Constants *)
+
+Theorem eval_addrsymbol:
+ forall le id ofs,
+ exists v, eval_expr ge sp e m le (addrsymbol id ofs) v /\ Val.lessdef (Genv.symbol_address ge id ofs) v.
+Proof.
+ intros. unfold addrsymbol. TrivialExists.
+Qed.
+
+Theorem eval_addrstack:
+ forall le ofs,
+ exists v, eval_expr ge sp e m le (addrstack ofs) v /\ Val.lessdef (Val.offset_ptr sp ofs) v.
+Proof.
+ intros. unfold addrstack. TrivialExists.
+Qed.
+
+(** ** Addition, opposite, subtraction *)
+
+Theorem eval_addimm:
+ forall n, unary_constructor_sound (addimm n) (fun x => Val.add x (Vint n)).
+Proof.
+ red; unfold addimm; intros until x.
+ predSpec Int.eq Int.eq_spec n Int.zero.
+- subst n. intros. exists x; split; auto.
+ destruct x; simpl; auto. rewrite Int.add_zero; auto.
+- case (addimm_match a); intros; InvEval; simpl; TrivialExists; simpl.
++ rewrite Int.add_commut. auto.
++ subst x. rewrite Val.add_assoc. rewrite Int.add_commut. auto.
+Qed.
+
+Theorem eval_add: binary_constructor_sound add Val.add.
+Proof.
+ red; intros until y.
+ unfold add; case (add_match a b); intros; InvEval; subst.
+- rewrite Val.add_commut. apply eval_addimm; auto.
+- apply eval_addimm; auto.
+- replace (Val.add (Val.add v1 (Vint n1)) (Val.add v0 (Vint n2)))
+ with (Val.add (Val.add v1 v0) (Val.add (Vint n1) (Vint n2))).
+ apply eval_addimm. EvalOp.
+ repeat rewrite Val.add_assoc. decEq. apply Val.add_permut.
+- replace (Val.add (Val.add v1 (Vint n1)) y)
+ with (Val.add (Val.add v1 y) (Vint n1)).
+ apply eval_addimm. EvalOp.
+ repeat rewrite Val.add_assoc. decEq. apply Val.add_commut.
+- rewrite <- Val.add_assoc. apply eval_addimm. EvalOp.
+- rewrite Val.add_commut. TrivialExists.
+- TrivialExists.
+- rewrite Val.add_commut. TrivialExists.
+- TrivialExists.
+- TrivialExists.
+Qed.
+
+Theorem eval_negint: unary_constructor_sound negint (fun v => Val.sub Vzero v).
+Proof.
+ red; intros until x; unfold negint. case (negint_match a); intros; InvEval; subst.
+- TrivialExists.
+- TrivialExists.
+- TrivialExists.
+Qed.
+
+Theorem eval_sub: binary_constructor_sound sub Val.sub.
+Proof.
+ red; intros until y; unfold sub; case (sub_match a b); intros; InvEval; subst.
+- rewrite Val.sub_add_opp. apply eval_addimm; auto.
+- rewrite Val.sub_add_l. rewrite Val.sub_add_r.
+ rewrite Val.add_assoc. simpl. rewrite Int.add_commut. rewrite <- Int.sub_add_opp.
+ apply eval_addimm; EvalOp.
+- rewrite Val.sub_add_l. apply eval_addimm; EvalOp.
+- rewrite Val.sub_add_r. apply eval_addimm; EvalOp.
+- TrivialExists.
+- TrivialExists.
+- TrivialExists.
+Qed.
+
+(** ** Immediate shifts *)
+
+Remark eval_shlimm_base: forall le a n x,
+ eval_expr ge sp e m le a x ->
+ Int.ltu n Int.iwordsize = true ->
+ eval_expr ge sp e m le (shlimm_base a n) (Val.shl x (Vint n)).
+Proof.
+Local Opaque mk_amount32.
+ unfold shlimm_base; intros; EvalOp. simpl. rewrite mk_amount32_eq by auto. auto.
+Qed.
+
+Theorem eval_shlimm:
+ forall n, unary_constructor_sound (fun a => shlimm a n)
+ (fun x => Val.shl x (Vint n)).
+Proof.
+ red; intros until x; unfold shlimm.
+ predSpec Int.eq Int.eq_spec n Int.zero; [| destruct (Int.ltu n Int.iwordsize) eqn:L]; simpl.
+- intros; subst. exists x; split; auto. destruct x; simpl; auto. rewrite Int.shl_zero; auto.
+- destruct (shlimm_match a); intros; InvEval; subst.
++ TrivialExists. simpl; rewrite L; auto.
++ destruct (Int.ltu (Int.add a n) Int.iwordsize) eqn:L2.
+* econstructor; split. eapply eval_shlimm_base; eauto.
+ destruct v1; simpl; auto. rewrite a32_range; simpl. rewrite L, L2.
+ rewrite Int.shl_shl; auto using a32_range.
+* econstructor; split; [|eauto]. apply eval_shlimm_base; auto. EvalOp.
++ TrivialExists. simpl. rewrite mk_amount32_eq; auto.
++ TrivialExists. simpl. rewrite mk_amount32_eq; auto.
++ destruct (Int.ltu (Int.add a n) Int.iwordsize) eqn:L2.
+* TrivialExists. simpl. rewrite mk_amount32_eq by auto.
+ destruct (Val.zero_ext s v1); simpl; auto.
+ rewrite a32_range; simpl; rewrite L, L2.
+ rewrite Int.shl_shl; auto using a32_range.
+* econstructor; split. eapply eval_shlimm_base; eauto. EvalOp; simpl; eauto. auto.
++ destruct (Int.ltu (Int.add a n) Int.iwordsize) eqn:L2.
+* TrivialExists. simpl. rewrite mk_amount32_eq by auto.
+ destruct (Val.sign_ext s v1); simpl; auto.
+ rewrite a32_range; simpl; rewrite L, L2.
+ rewrite Int.shl_shl; auto using a32_range.
+* econstructor; split. eapply eval_shlimm_base; eauto. EvalOp; simpl; eauto. auto.
++ econstructor; eauto using eval_shlimm_base.
+- intros; TrivialExists.
+Qed.
+
+Remark eval_shruimm_base: forall le a n x,
+ eval_expr ge sp e m le a x ->
+ Int.ltu n Int.iwordsize = true ->
+ eval_expr ge sp e m le (shruimm_base a n) (Val.shru x (Vint n)).
+Proof.
+ unfold shruimm_base; intros; EvalOp. simpl. rewrite mk_amount32_eq by auto. auto.
+Qed.
+
+Remark sub_shift_amount:
+ forall y z,
+ Int.ltu y Int.iwordsize = true -> Int.ltu z Int.iwordsize = true -> Int.unsigned y <= Int.unsigned z ->
+ Int.ltu (Int.sub z y) Int.iwordsize = true.
+Proof.
+ intros. unfold Int.ltu; apply zlt_true. rewrite Int.unsigned_repr_wordsize.
+ apply Int.ltu_iwordsize_inv in H. apply Int.ltu_iwordsize_inv in H0.
+ unfold Int.sub; rewrite Int.unsigned_repr. omega.
+ generalize Int.wordsize_max_unsigned; omega.
+Qed.
+
+Theorem eval_shruimm:
+ forall n, unary_constructor_sound (fun a => shruimm a n)
+ (fun x => Val.shru x (Vint n)).
+Proof.
+Local Opaque Int.zwordsize.
+ red; intros until x; unfold shruimm.
+ predSpec Int.eq Int.eq_spec n Int.zero; [| destruct (Int.ltu n Int.iwordsize) eqn:L]; simpl.
+- intros; subst. exists x; split; auto. destruct x; simpl; auto. rewrite Int.shru_zero; auto.
+- destruct (shruimm_match a); intros; InvEval; subst.
++ TrivialExists. simpl; rewrite L; auto.
++ destruct (Int.ltu n a) eqn:L2.
+* assert (L3: Int.ltu (Int.sub a n) Int.iwordsize = true).
+ { apply sub_shift_amount; auto using a32_range.
+ apply Int.ltu_inv in L2. omega. }
+ econstructor; split. EvalOp.
+ destruct v1; simpl; auto. rewrite mk_amount32_eq, L3, a32_range by auto.
+ simpl. rewrite L. rewrite Int.shru_shl, L2 by auto using a32_range. auto.
+* assert (L3: Int.ltu (Int.sub n a) Int.iwordsize = true).
+ { apply sub_shift_amount; auto using a32_range.
+ unfold Int.ltu in L2. destruct zlt in L2; discriminate || omega. }
+ econstructor; split. EvalOp.
+ destruct v1; simpl; auto. rewrite mk_amount32_eq, L3, a32_range by auto.
+ simpl. rewrite L. rewrite Int.shru_shl, L2 by auto using a32_range. auto.
++ destruct (Int.ltu (Int.add a n) Int.iwordsize) eqn:L2.
+* econstructor; split. eapply eval_shruimm_base; eauto.
+ destruct v1; simpl; auto. rewrite a32_range; simpl. rewrite L, L2.
+ rewrite Int.shru_shru; auto using a32_range.
+* econstructor; split; [|eauto]. apply eval_shruimm_base; auto. EvalOp.
++ destruct (zlt (Int.unsigned n) s).
+* econstructor; split. EvalOp. rewrite mk_amount32_eq by auto.
+ destruct v1; simpl; auto. rewrite ! L; simpl.
+ set (s' := s - Int.unsigned n).
+ replace s with (s' + Int.unsigned n) by (unfold s'; omega).
+ rewrite Int.shru_zero_ext. auto. unfold s'; omega.
+* econstructor; split. EvalOp.
+ destruct v1; simpl; auto. rewrite ! L; simpl.
+ rewrite Int.shru_zero_ext_0 by omega. auto.
++ econstructor; eauto using eval_shruimm_base.
+- intros; TrivialExists.
+Qed.
+
+Remark eval_shrimm_base: forall le a n x,
+ eval_expr ge sp e m le a x ->
+ Int.ltu n Int.iwordsize = true ->
+ eval_expr ge sp e m le (shrimm_base a n) (Val.shr x (Vint n)).
+Proof.
+ unfold shrimm_base; intros; EvalOp. simpl. rewrite mk_amount32_eq by auto. auto.
+Qed.
+
+Theorem eval_shrimm:
+ forall n, unary_constructor_sound (fun a => shrimm a n)
+ (fun x => Val.shr x (Vint n)).
+Proof.
+ red; intros until x; unfold shrimm.
+ predSpec Int.eq Int.eq_spec n Int.zero; [| destruct (Int.ltu n Int.iwordsize) eqn:L]; simpl.
+- intros; subst. exists x; split; auto. destruct x; simpl; auto. rewrite Int.shr_zero; auto.
+- destruct (shrimm_match a); intros; InvEval; subst.
++ TrivialExists. simpl; rewrite L; auto.
++ destruct (Int.ltu n a) eqn:L2.
+* assert (L3: Int.ltu (Int.sub a n) Int.iwordsize = true).
+ { apply sub_shift_amount; auto using a32_range.
+ apply Int.ltu_inv in L2. omega. }
+ econstructor; split. EvalOp.
+ destruct v1; simpl; auto. rewrite mk_amount32_eq, L3, a32_range by auto.
+ simpl. rewrite L. rewrite Int.shr_shl, L2 by auto using a32_range. auto.
+* assert (L3: Int.ltu (Int.sub n a) Int.iwordsize = true).
+ { apply sub_shift_amount; auto using a32_range.
+ unfold Int.ltu in L2. destruct zlt in L2; discriminate || omega. }
+ econstructor; split. EvalOp.
+ destruct v1; simpl; auto. rewrite mk_amount32_eq, L3, a32_range by auto.
+ simpl. rewrite L. rewrite Int.shr_shl, L2 by auto using a32_range. auto.
++ destruct (Int.ltu (Int.add a n) Int.iwordsize) eqn:L2.
+* econstructor; split. eapply eval_shrimm_base; eauto.
+ destruct v1; simpl; auto. rewrite a32_range; simpl. rewrite L, L2.
+ rewrite Int.shr_shr; auto using a32_range.
+* econstructor; split; [|eauto]. apply eval_shrimm_base; auto. EvalOp.
++ destruct (zlt (Int.unsigned n) s && zlt s Int.zwordsize) eqn:E.
+* InvBooleans. econstructor; split. EvalOp. rewrite mk_amount32_eq by auto.
+ destruct v1; simpl; auto. rewrite ! L; simpl.
+ set (s' := s - Int.unsigned n).
+ replace s with (s' + Int.unsigned n) by (unfold s'; omega).
+ rewrite Int.shr_sign_ext. auto. unfold s'; omega. unfold s'; omega.
+* econstructor; split; [|eauto]. apply eval_shrimm_base; auto. EvalOp.
++ econstructor; eauto using eval_shrimm_base.
+- intros; TrivialExists.
+Qed.
+
+(** ** Multiplication *)
+
+Lemma eval_mulimm_base:
+ forall n, unary_constructor_sound (mulimm_base n) (fun x => Val.mul x (Vint n)).
+Proof.
+ intros; red; intros; unfold mulimm_base.
+ assert (DFL: exists v, eval_expr ge sp e m le (Eop Omul (Eop (Ointconst n) Enil ::: a ::: Enil)) v /\ Val.lessdef (Val.mul x (Vint n)) v).
+ { rewrite Val.mul_commut; TrivialExists. }
+ generalize (Int.one_bits_decomp n); generalize (Int.one_bits_range n);
+ destruct (Int.one_bits n) as [ | i [ | j []]]; intros P Q.
+- apply DFL.
+- replace (Val.mul x (Vint n)) with (Val.shl x (Vint i)).
+ apply eval_shlimm; auto.
+ simpl in Q. rewrite <- Val.shl_mul, Q, Int.add_zero. simpl. rewrite P by auto with coqlib. auto.
+- exploit (eval_shlimm i (x :: le) (Eletvar 0) x). constructor; auto. intros [v1 [A1 B1]].
+ exploit (eval_shlimm j (x :: le) (Eletvar 0) x). constructor; auto. intros [v2 [A2 B2]].
+ exploit (eval_add (x :: le)). eexact A1. eexact A2. intros [v [A B]].
+ exists v; split. econstructor; eauto.
+ simpl in Q. rewrite Q, Int.add_zero.
+ replace (Vint (Int.add (Int.shl Int.one i) (Int.shl Int.one j)))
+ with (Val.add (Val.shl Vone (Vint i)) (Val.shl Vone (Vint j))).
+ rewrite Val.mul_add_distr_r.
+ repeat rewrite Val.shl_mul. eapply Val.lessdef_trans; [|eauto]. apply Val.add_lessdef; auto.
+ simpl. repeat rewrite P by auto with coqlib. auto.
+- apply DFL.
+Qed.
+
+Theorem eval_mulimm:
+ forall n, unary_constructor_sound (mulimm n) (fun x => Val.mul x (Vint n)).
+Proof.
+ intros; red; intros until x; unfold mulimm.
+ predSpec Int.eq Int.eq_spec n Int.zero.
+ intros. exists (Vint Int.zero); split. EvalOp.
+ destruct x; simpl; auto. subst n. rewrite Int.mul_zero. auto.
+ predSpec Int.eq Int.eq_spec n Int.one.
+ intros. exists x; split; auto.
+ destruct x; simpl; auto. subst n. rewrite Int.mul_one. auto.
+ case (mulimm_match a); intros; InvEval; subst.
+- TrivialExists. simpl. rewrite Int.mul_commut; auto.
+- rewrite Val.mul_add_distr_l.
+ exploit eval_mulimm_base; eauto. instantiate (1 := n). intros [v' [A1 B1]].
+ exploit (eval_addimm (Int.mul n n2) le (mulimm_base n t2) v'). auto. intros [v'' [A2 B2]].
+ exists v''; split; auto. eapply Val.lessdef_trans. eapply Val.add_lessdef; eauto.
+ rewrite Val.mul_commut; auto.
+- apply eval_mulimm_base; auto.
+Qed.
+
+Theorem eval_mul: binary_constructor_sound mul Val.mul.
+Proof.
+ red; intros until y; unfold mul; case (mul_match a b); intros; InvEval; subst.
+- rewrite Val.mul_commut. apply eval_mulimm; auto.
+- apply eval_mulimm; auto.
+- TrivialExists.
+Qed.
+
+Theorem eval_mulhs: binary_constructor_sound mulhs Val.mulhs.
+Proof.
+ unfold mulhs; red; intros. econstructor; split. EvalOp.
+ unfold eval_shiftl, eval_extend. rewrite ! mk_amount64_eq by auto.
+ destruct x; simpl; auto. destruct y; simpl; auto.
+ change (Int.ltu Int.zero Int64.iwordsize') with true; simpl.
+ rewrite ! Int64.shl'_zero.
+ change (Int.ltu (Int.repr 32) Int64.iwordsize') with true; simpl.
+ apply Val.lessdef_same. f_equal.
+ transitivity (Int.repr (Z.shiftr (Int.signed i * Int.signed i0) 32)).
+ unfold Int.mulhs; f_equal. rewrite Zshiftr_div_two_p by omega. reflexivity.
+ apply Int.same_bits_eq; intros n N.
+ change Int.zwordsize with 32 in *.
+ assert (N1: 0 <= n < 64) by omega.
+ rewrite Int64.bits_loword by auto.
+ rewrite Int64.bits_shr' by auto.
+ change (Int.unsigned (Int.repr 32)) with 32. change Int64.zwordsize with 64.
+ rewrite zlt_true by omega.
+ rewrite Int.testbit_repr by auto.
+ unfold Int64.mul. rewrite Int64.testbit_repr by (change Int64.zwordsize with 64; omega).
+ transitivity (Z.testbit (Int.signed i * Int.signed i0) (n + 32)).
+ rewrite Z.shiftr_spec by omega. auto.
+ apply Int64.same_bits_eqm. apply Int64.eqm_mult; apply Int64.eqm_unsigned_repr.
+ change Int64.zwordsize with 64; omega.
+Qed.
+
+Theorem eval_mulhu: binary_constructor_sound mulhu Val.mulhu.
+Proof.
+ unfold mulhu; red; intros. econstructor; split. EvalOp.
+ unfold eval_shiftl, eval_extend. rewrite ! mk_amount64_eq by auto.
+ destruct x; simpl; auto. destruct y; simpl; auto.
+ change (Int.ltu Int.zero Int64.iwordsize') with true; simpl.
+ rewrite ! Int64.shl'_zero.
+ change (Int.ltu (Int.repr 32) Int64.iwordsize') with true; simpl.
+ apply Val.lessdef_same. f_equal.
+ transitivity (Int.repr (Z.shiftr (Int.unsigned i * Int.unsigned i0) 32)).
+ unfold Int.mulhu; f_equal. rewrite Zshiftr_div_two_p by omega. reflexivity.
+ apply Int.same_bits_eq; intros n N.
+ change Int.zwordsize with 32 in *.
+ assert (N1: 0 <= n < 64) by omega.
+ rewrite Int64.bits_loword by auto.
+ rewrite Int64.bits_shru' by auto.
+ change (Int.unsigned (Int.repr 32)) with 32. change Int64.zwordsize with 64.
+ rewrite zlt_true by omega.
+ rewrite Int.testbit_repr by auto.
+ unfold Int64.mul. rewrite Int64.testbit_repr by (change Int64.zwordsize with 64; omega).
+ transitivity (Z.testbit (Int.unsigned i * Int.unsigned i0) (n + 32)).
+ rewrite Z.shiftr_spec by omega. auto.
+ apply Int64.same_bits_eqm. apply Int64.eqm_mult; apply Int64.eqm_unsigned_repr.
+ change Int64.zwordsize with 64; omega.
+Qed.
+
+(** Integer conversions *)
+
+Theorem eval_zero_ext:
+ forall sz, 0 <= sz -> unary_constructor_sound (zero_ext sz) (Val.zero_ext sz).
+Proof.
+ intros; red; intros until x; unfold zero_ext; case (zero_ext_match a); intros; InvEval; subst.
+- TrivialExists.
+- TrivialExists.
+- destruct (zlt (Int.unsigned a0) sz).
++ econstructor; split. EvalOp. destruct v1; simpl; auto. rewrite a32_range; simpl.
+ apply Val.lessdef_same. f_equal. rewrite Int.shl_zero_ext by omega. f_equal. omega.
++ TrivialExists.
+- TrivialExists.
+Qed.
+
+Theorem eval_sign_ext:
+ forall sz, 0 < sz -> unary_constructor_sound (sign_ext sz) (Val.sign_ext sz).
+Proof.
+ intros; red; intros until x; unfold sign_ext; case (sign_ext_match a); intros; InvEval; subst.
+- TrivialExists.
+- TrivialExists.
+- destruct (zlt (Int.unsigned a0) sz).
++ econstructor; split. EvalOp. destruct v1; simpl; auto. rewrite a32_range; simpl.
+ apply Val.lessdef_same. f_equal. rewrite Int.shl_sign_ext by omega. f_equal. omega.
++ TrivialExists.
+- TrivialExists.
+Qed.
+
+Theorem eval_cast8signed: unary_constructor_sound cast8signed (Val.sign_ext 8).
+Proof.
+ apply eval_sign_ext; omega.
+Qed.
+
+Theorem eval_cast8unsigned: unary_constructor_sound cast8unsigned (Val.zero_ext 8).
+Proof.
+ apply eval_zero_ext; omega.
+Qed.
+
+Theorem eval_cast16signed: unary_constructor_sound cast16signed (Val.sign_ext 16).
+Proof.
+ apply eval_sign_ext; omega.
+Qed.
+
+Theorem eval_cast16unsigned: unary_constructor_sound cast16unsigned (Val.zero_ext 16).
+Proof.
+ apply eval_zero_ext; omega.
+Qed.
+
+(** Bitwise not, and, or, xor *)
+
+Theorem eval_notint: unary_constructor_sound notint Val.notint.
+Proof.
+ assert (INV: forall v, Val.lessdef (Val.notint (Val.notint v)) v).
+ { destruct v; auto. simpl; rewrite Int.not_involutive; auto. }
+ unfold notint; red; intros until x; case (notint_match a); intros; InvEval; subst.
+- TrivialExists.
+- TrivialExists.
+- exists v1; auto.
+- exists (eval_shift s v1 a0); split; auto. EvalOp.
+- econstructor; split. EvalOp.
+ destruct v1; simpl; auto; destruct v0; simpl; auto.
+ rewrite Int.not_and_or_not, Int.not_involutive, Int.or_commut. auto.
+- econstructor; split. EvalOp.
+ destruct v1; simpl; auto; destruct v0; simpl; auto.
+ rewrite Int.not_or_and_not, Int.not_involutive, Int.and_commut. auto.
+- econstructor; split. EvalOp.
+ rewrite ! Val.not_xor, Val.xor_assoc; auto.
+- econstructor; split. EvalOp.
+ destruct v1; simpl; auto; destruct v0; simpl; auto.
+ unfold Int.not; rewrite ! Int.xor_assoc, Int.xor_idem, Int.xor_zero. auto.
+- TrivialExists.
+Qed.
+
+Lemma eval_andimm_base:
+ forall n, unary_constructor_sound (andimm_base n) (fun x => Val.and x (Vint n)).
+Proof.
+ intros; red; intros. unfold andimm_base.
+ predSpec Int.eq Int.eq_spec n Int.zero.
+ exists (Vint Int.zero); split. EvalOp.
+ destruct x; simpl; auto. subst n. rewrite Int.and_zero. auto.
+ predSpec Int.eq Int.eq_spec n Int.mone.
+ exists x; split; auto.
+ subst. destruct x; simpl; auto. rewrite Int.and_mone; auto.
+ destruct (Z_is_power2m1 (Int.unsigned n)) as [s|] eqn:P.
+ assert (0 <= s) by (eapply Z_is_power2m1_nonneg; eauto).
+ rewrite <- (Int.repr_unsigned n), (Z_is_power2m1_sound _ _ P), <- Val.zero_ext_and by auto.
+ apply eval_zero_ext; auto.
+ TrivialExists.
+Qed.
+
+Theorem eval_andimm:
+ forall n, unary_constructor_sound (andimm n) (fun x => Val.and x (Vint n)).
+Proof.
+ intros; red; intros until x. unfold andimm.
+ case (andimm_match a); intros; InvEval; subst.
+- rewrite Int.and_commut; TrivialExists.
+- rewrite Val.and_assoc, Int.and_commut. apply eval_andimm_base; auto.
+- destruct (zle 0 s).
++ rewrite Val.zero_ext_and, Val.and_assoc, Int.and_commut by auto.
+ apply eval_andimm_base; auto.
++ apply eval_andimm_base. EvalOp.
+- apply eval_andimm_base; auto.
+Qed.
+
+Theorem eval_and: binary_constructor_sound and Val.and.
+Proof.
+ red; intros until y; unfold and; case (and_match a b); intros; InvEval; subst.
+- rewrite Val.and_commut; apply eval_andimm; auto.
+- apply eval_andimm; auto.
+- rewrite Val.and_commut; TrivialExists.
+- TrivialExists.
+- rewrite Val.and_commut; TrivialExists.
+- TrivialExists.
+- rewrite Val.and_commut; TrivialExists.
+- TrivialExists.
+- TrivialExists.
+Qed.
+
+Theorem eval_orimm:
+ forall n, unary_constructor_sound (orimm n) (fun x => Val.or x (Vint n)).
+Proof.
+ intros; red; intros until x. unfold orimm.
+ predSpec Int.eq Int.eq_spec n Int.zero.
+ intros. subst. exists x; split; auto.
+ destruct x; simpl; auto. rewrite Int.or_zero; auto.
+ predSpec Int.eq Int.eq_spec n Int.mone.
+ intros. exists (Vint Int.mone); split. EvalOp.
+ destruct x; simpl; auto. subst n. rewrite Int.or_mone. auto.
+ destruct (orimm_match a); intros; InvEval; subst.
+- rewrite Int.or_commut; TrivialExists.
+- rewrite Val.or_assoc, Int.or_commut; TrivialExists.
+- TrivialExists.
+Qed.
+
+Remark eval_same_expr:
+ forall a1 a2 le v1 v2,
+ same_expr_pure a1 a2 = true ->
+ eval_expr ge sp e m le a1 v1 ->
+ eval_expr ge sp e m le a2 v2 ->
+ a1 = a2 /\ v1 = v2.
+Proof.
+ intros. destruct a1; try discriminate. destruct a2; try discriminate.
+ simpl in H; destruct (ident_eq i i0); inv H.
+ split. auto. inv H0; inv H1; congruence.
+Qed.
+
+Theorem eval_or: binary_constructor_sound or Val.or.
+Proof.
+ red; intros until y; unfold or; case (or_match a b); intros; InvEval; subst.
+- rewrite Val.or_commut. apply eval_orimm; auto.
+- apply eval_orimm; auto.
+- rewrite Val.or_commut; TrivialExists.
+- TrivialExists.
+- rewrite Val.or_commut; TrivialExists.
+- TrivialExists.
+- (* shl - shru *)
+ destruct (Int.eq (Int.add a1 a2) Int.iwordsize && same_expr_pure t1 t2) eqn:?.
++ InvBooleans. apply Int.same_if_eq in H.
+ exploit eval_same_expr; eauto. intros [EQ1 EQ2]. subst.
+ econstructor; split. EvalOp.
+ destruct v0; simpl; auto. rewrite ! a32_range. simpl. rewrite <- Int.or_ror; auto using a32_range.
++ TrivialExists.
+- (* shru - shl *)
+ destruct (Int.eq (Int.add a2 a1) Int.iwordsize && same_expr_pure t1 t2) eqn:?.
++ InvBooleans. apply Int.same_if_eq in H.
+ exploit eval_same_expr; eauto. intros [EQ1 EQ2]. subst.
+ econstructor; split. EvalOp.
+ destruct v0; simpl; auto. rewrite ! a32_range. simpl.
+ rewrite Int.or_commut, <- Int.or_ror; auto using a32_range.
++ TrivialExists.
+- rewrite Val.or_commut; TrivialExists.
+- TrivialExists.
+- TrivialExists.
+Qed.
+
+Lemma eval_xorimm_base:
+ forall n, unary_constructor_sound (xorimm_base n) (fun x => Val.xor x (Vint n)).
+Proof.
+ intros; red; intros. unfold xorimm_base.
+ predSpec Int.eq Int.eq_spec n Int.zero.
+ intros. exists x; split. auto.
+ destruct x; simpl; auto. subst n. rewrite Int.xor_zero. auto.
+ predSpec Int.eq Int.eq_spec n Int.mone.
+ subst n. rewrite <- Val.not_xor. apply eval_notint; auto.
+ TrivialExists.
+Qed.
+
+Theorem eval_xorimm:
+ forall n, unary_constructor_sound (xorimm n) (fun x => Val.xor x (Vint n)).
+Proof.
+ intros; red; intros until x. unfold xorimm.
+ destruct (xorimm_match a); intros; InvEval; subst.
+- rewrite Int.xor_commut; TrivialExists.
+- rewrite Val.xor_assoc; simpl. rewrite (Int.xor_commut n2). apply eval_xorimm_base; auto.
+- apply eval_xorimm_base; auto.
+Qed.
+
+Theorem eval_xor: binary_constructor_sound xor Val.xor.
+Proof.
+ red; intros until y; unfold xor; case (xor_match a b); intros; InvEval; subst.
+- rewrite Val.xor_commut; apply eval_xorimm; auto.
+- apply eval_xorimm; auto.
+- rewrite Val.xor_commut; TrivialExists.
+- TrivialExists.
+- rewrite Val.xor_commut; TrivialExists.
+- TrivialExists.
+- rewrite Val.xor_commut; TrivialExists.
+- TrivialExists.
+- TrivialExists.
+Qed.
+
+(** ** Integer division and modulus *)
+
+Theorem eval_divs_base:
+ forall le a b x y z,
+ eval_expr ge sp e m le a x ->
+ eval_expr ge sp e m le b y ->
+ Val.divs x y = Some z ->
+ exists v, eval_expr ge sp e m le (divs_base a b) v /\ Val.lessdef z v.
+Proof.
+ intros; unfold divs_base; TrivialExists.
+Qed.
+
+Theorem eval_mods_base:
+ forall le a b x y z,
+ eval_expr ge sp e m le a x ->
+ eval_expr ge sp e m le b y ->
+ Val.mods x y = Some z ->
+ exists v, eval_expr ge sp e m le (mods_base a b) v /\ Val.lessdef z v.
+Proof.
+ intros; unfold mods_base, mod_aux.
+ exploit Val.mods_divs; eauto. intros (q & A & B). subst z.
+ TrivialExists. repeat (econstructor; eauto with evalexpr). exact A.
+Qed.
+
+Theorem eval_divu_base:
+ forall le a x b y z,
+ eval_expr ge sp e m le a x ->
+ eval_expr ge sp e m le b y ->
+ Val.divu x y = Some z ->
+ exists v, eval_expr ge sp e m le (divu_base a b) v /\ Val.lessdef z v.
+Proof.
+ intros; unfold divu_base; TrivialExists.
+Qed.
+
+Theorem eval_modu_base:
+ forall le a x b y z,
+ eval_expr ge sp e m le a x ->
+ eval_expr ge sp e m le b y ->
+ Val.modu x y = Some z ->
+ exists v, eval_expr ge sp e m le (modu_base a b) v /\ Val.lessdef z v.
+Proof.
+ intros; unfold modu_base, mod_aux.
+ exploit Val.modu_divu; eauto. intros (q & A & B). subst z.
+ TrivialExists. repeat (econstructor; eauto with evalexpr). exact A.
+Qed.
+
+Theorem eval_shrximm:
+ forall le a n x z,
+ eval_expr ge sp e m le a x ->
+ Val.shrx x (Vint n) = Some z ->
+ exists v, eval_expr ge sp e m le (shrximm a n) v /\ Val.lessdef z v.
+Proof.
+ intros; unfold shrximm.
+ predSpec Int.eq Int.eq_spec n Int.zero.
+- subst n. exists x; split; auto.
+ destruct x; simpl in H0; try discriminate.
+ change (Int.ltu Int.zero (Int.repr 31)) with true in H0; inv H0.
+ rewrite Int.shrx_zero by (compute; auto). auto.
+- TrivialExists.
+Qed.
+
+(** General shifts *)
+
+Theorem eval_shl: binary_constructor_sound shl Val.shl.
+Proof.
+ red; intros until y; unfold shl; case (shl_match b); intros.
+ InvEval. apply eval_shlimm; auto.
+ TrivialExists.
+Qed.
+
+Theorem eval_shr: binary_constructor_sound shr Val.shr.
+Proof.
+ red; intros until y; unfold shr; case (shr_match b); intros.
+ InvEval. apply eval_shrimm; auto.
+ TrivialExists.
+Qed.
+
+Theorem eval_shru: binary_constructor_sound shru Val.shru.
+Proof.
+ red; intros until y; unfold shru; case (shru_match b); intros.
+ InvEval. apply eval_shruimm; auto.
+ TrivialExists.
+Qed.
+
+(** Floating-point operations *)
+
+Theorem eval_negf: unary_constructor_sound negf Val.negf.
+Proof.
+ red; intros; TrivialExists.
+Qed.
+
+Theorem eval_absf: unary_constructor_sound absf Val.absf.
+Proof.
+ red; intros; TrivialExists.
+Qed.
+
+Theorem eval_addf: binary_constructor_sound addf Val.addf.
+Proof.
+ red; intros; TrivialExists.
+Qed.
+
+Theorem eval_subf: binary_constructor_sound subf Val.subf.
+Proof.
+ red; intros; TrivialExists.
+Qed.
+
+Theorem eval_mulf: binary_constructor_sound mulf Val.mulf.
+Proof.
+ red; intros; TrivialExists.
+Qed.
+
+Theorem eval_negfs: unary_constructor_sound negfs Val.negfs.
+Proof.
+ red; intros; TrivialExists.
+Qed.
+
+Theorem eval_absfs: unary_constructor_sound absfs Val.absfs.
+Proof.
+ red; intros; TrivialExists.
+Qed.
+
+Theorem eval_addfs: binary_constructor_sound addfs Val.addfs.
+Proof.
+ red; intros; TrivialExists.
+Qed.
+
+Theorem eval_subfs: binary_constructor_sound subfs Val.subfs.
+Proof.
+ red; intros; TrivialExists.
+Qed.
+
+Theorem eval_mulfs: binary_constructor_sound mulfs Val.mulfs.
+Proof.
+ red; intros; TrivialExists.
+Qed.
+
+Section COMP_IMM.
+
+Variable default: comparison -> int -> condition.
+Variable intsem: comparison -> int -> int -> bool.
+Variable sem: comparison -> val -> val -> val.
+
+Hypothesis sem_int: forall c x y, sem c (Vint x) (Vint y) = Val.of_bool (intsem c x y).
+Hypothesis sem_undef: forall c v, sem c Vundef v = Vundef.
+Hypothesis sem_eq: forall x y, sem Ceq (Vint x) (Vint y) = Val.of_bool (Int.eq x y).
+Hypothesis sem_ne: forall x y, sem Cne (Vint x) (Vint y) = Val.of_bool (negb (Int.eq x y)).
+Hypothesis sem_default: forall c v n, sem c v (Vint n) = Val.of_optbool (eval_condition (default c n) (v :: nil) m).
+
+Lemma eval_compimm:
+ forall le c a n2 x,
+ eval_expr ge sp e m le a x ->
+ exists v, eval_expr ge sp e m le (compimm default intsem c a n2) v
+ /\ Val.lessdef (sem c x (Vint n2)) v.
+Proof.
+ intros until x.
+ unfold compimm; case (compimm_match c a); intros; InvEval; subst.
+- (* constant *)
+ rewrite sem_int. TrivialExists. simpl. destruct (intsem c0 n1 n2); auto.
+- (* eq cmp *)
+ inv H. simpl in H5. inv H5.
+ destruct (Int.eq_dec n2 Int.zero). subst n2. TrivialExists.
+ simpl. rewrite eval_negate_condition.
+ destruct (eval_condition c0 vl m); simpl.
+ unfold Vtrue, Vfalse. destruct b; simpl; rewrite sem_eq; auto.
+ rewrite sem_undef; auto.
+ destruct (Int.eq_dec n2 Int.one). subst n2. TrivialExists.
+ simpl. destruct (eval_condition c0 vl m); simpl.
+ unfold Vtrue, Vfalse. destruct b; simpl; rewrite sem_eq; auto.
+ rewrite sem_undef; auto.
+ exists (Vint Int.zero); split. EvalOp.
+ destruct (eval_condition c0 vl m); simpl.
+ unfold Vtrue, Vfalse. destruct b; rewrite sem_eq; rewrite Int.eq_false; auto.
+ rewrite sem_undef; auto.
+- (* ne cmp *)
+ inv H. simpl in H5. inv H5.
+ destruct (Int.eq_dec n2 Int.zero). subst n2. TrivialExists.
+ simpl. destruct (eval_condition c0 vl m); simpl.
+ unfold Vtrue, Vfalse. destruct b; simpl; rewrite sem_ne; auto.
+ rewrite sem_undef; auto.
+ destruct (Int.eq_dec n2 Int.one). subst n2. TrivialExists.
+ simpl. rewrite eval_negate_condition. destruct (eval_condition c0 vl m); simpl.
+ unfold Vtrue, Vfalse. destruct b; simpl; rewrite sem_ne; auto.
+ rewrite sem_undef; auto.
+ exists (Vint Int.one); split. EvalOp.
+ destruct (eval_condition c0 vl m); simpl.
+ unfold Vtrue, Vfalse. destruct b; rewrite sem_ne; rewrite Int.eq_false; auto.
+ rewrite sem_undef; auto.
+- (* mask zero *)
+ predSpec Int.eq Int.eq_spec n2 Int.zero.
++ subst n2. econstructor; split. EvalOp. simpl.
+ destruct v1; simpl; try (rewrite sem_undef; auto).
+ rewrite sem_eq. destruct (Int.eq (Int.and i m0) Int.zero); auto.
++ TrivialExists. simpl. rewrite sem_default. auto.
+- (* mask not zero *)
+ predSpec Int.eq Int.eq_spec n2 Int.zero.
++ subst n2. econstructor; split. EvalOp. simpl.
+ destruct v1; simpl; try (rewrite sem_undef; auto).
+ rewrite sem_ne. destruct (Int.eq (Int.and i m0) Int.zero); auto.
++ TrivialExists. simpl. rewrite sem_default. auto.
+- (* default *)
+ TrivialExists. simpl. rewrite sem_default. auto.
+Qed.
+
+Hypothesis sem_swap:
+ forall c x y, sem (swap_comparison c) x y = sem c y x.
+
+Lemma eval_compimm_swap:
+ forall le c a n2 x,
+ eval_expr ge sp e m le a x ->
+ exists v, eval_expr ge sp e m le (compimm default intsem (swap_comparison c) a n2) v
+ /\ Val.lessdef (sem c (Vint n2) x) v.
+Proof.
+ intros. rewrite <- sem_swap. eapply eval_compimm; eauto.
+Qed.
+
+End COMP_IMM.
+
+Theorem eval_comp:
+ forall c, binary_constructor_sound (comp c) (Val.cmp c).
+Proof.
+ intros; red; intros until y. unfold comp; case (comp_match a b); intros; InvEval; subst.
+- eapply eval_compimm_swap; eauto.
+ intros. unfold Val.cmp. rewrite Val.swap_cmp_bool; auto.
+- eapply eval_compimm; eauto.
+- TrivialExists. simpl. rewrite Val.swap_cmp_bool. auto.
+- TrivialExists.
+- TrivialExists.
+Qed.
+
+Theorem eval_compu:
+ forall c, binary_constructor_sound (compu c) (Val.cmpu (Mem.valid_pointer m) c).
+Proof.
+ intros; red; intros until y. unfold compu; case (compu_match a b); intros; InvEval; subst.
+- eapply eval_compimm_swap; eauto.
+ intros. unfold Val.cmpu. rewrite Val.swap_cmpu_bool; auto.
+- eapply eval_compimm; eauto.
+- TrivialExists. simpl. rewrite Val.swap_cmpu_bool. auto.
+- TrivialExists.
+- TrivialExists.
+Qed.
+
+Theorem eval_compf:
+ forall c, binary_constructor_sound (compf c) (Val.cmpf c).
+Proof.
+ intros; red; intros. unfold compf. TrivialExists.
+Qed.
+
+Theorem eval_compfs:
+ forall c, binary_constructor_sound (compfs c) (Val.cmpfs c).
+Proof.
+ intros; red; intros. unfold compfs. TrivialExists.
+Qed.
+
+(** Floating-point conversions *)
+
+Theorem eval_singleoffloat: unary_constructor_sound singleoffloat Val.singleoffloat.
+Proof.
+ red; intros; TrivialExists.
+Qed.
+
+Theorem eval_floatofsingle: unary_constructor_sound floatofsingle Val.floatofsingle.
+Proof.
+ red; intros; TrivialExists.
+Qed.
+
+Theorem eval_intoffloat:
+ forall le a x y,
+ eval_expr ge sp e m le a x ->
+ Val.intoffloat x = Some y ->
+ exists v, eval_expr ge sp e m le (intoffloat a) v /\ Val.lessdef y v.
+Proof.
+ intros; TrivialExists.
+Qed.
+
+Theorem eval_floatofint:
+ forall le a x y,
+ eval_expr ge sp e m le a x ->
+ Val.floatofint x = Some y ->
+ exists v, eval_expr ge sp e m le (floatofint a) v /\ Val.lessdef y v.
+Proof.
+ intros until y; unfold floatofint. case (floatofint_match a); intros; InvEval.
+- TrivialExists.
+- TrivialExists.
+Qed.
+
+Theorem eval_intuoffloat:
+ forall le a x y,
+ eval_expr ge sp e m le a x ->
+ Val.intuoffloat x = Some y ->
+ exists v, eval_expr ge sp e m le (intuoffloat a) v /\ Val.lessdef y v.
+Proof.
+ intros; TrivialExists.
+Qed.
+
+Theorem eval_floatofintu:
+ forall le a x y,
+ eval_expr ge sp e m le a x ->
+ Val.floatofintu x = Some y ->
+ exists v, eval_expr ge sp e m le (floatofintu a) v /\ Val.lessdef y v.
+Proof.
+ intros until y; unfold floatofintu. case (floatofintu_match a); intros; InvEval.
+- TrivialExists.
+- TrivialExists.
+Qed.
+
+Theorem eval_intofsingle:
+ forall le a x y,
+ eval_expr ge sp e m le a x ->
+ Val.intofsingle x = Some y ->
+ exists v, eval_expr ge sp e m le (intofsingle a) v /\ Val.lessdef y v.
+Proof.
+ intros; TrivialExists.
+Qed.
+
+Theorem eval_singleofint:
+ forall le a x y,
+ eval_expr ge sp e m le a x ->
+ Val.singleofint x = Some y ->
+ exists v, eval_expr ge sp e m le (singleofint a) v /\ Val.lessdef y v.
+Proof.
+ intros until y; unfold singleofint. case (singleofint_match a); intros; InvEval.
+- TrivialExists.
+- TrivialExists.
+Qed.
+
+Theorem eval_intuofsingle:
+ forall le a x y,
+ eval_expr ge sp e m le a x ->
+ Val.intuofsingle x = Some y ->
+ exists v, eval_expr ge sp e m le (intuofsingle a) v /\ Val.lessdef y v.
+Proof.
+ intros; TrivialExists.
+Qed.
+
+Theorem eval_singleofintu:
+ forall le a x y,
+ eval_expr ge sp e m le a x ->
+ Val.singleofintu x = Some y ->
+ exists v, eval_expr ge sp e m le (singleofintu a) v /\ Val.lessdef y v.
+Proof.
+ intros until y; unfold singleofintu. case (singleofintu_match a); intros; InvEval.
+- TrivialExists.
+- TrivialExists.
+Qed.
+
+(** Selection *)
+
+Theorem eval_select:
+ forall le ty cond al vl a1 v1 a2 v2 a b,
+ select ty cond al a1 a2 = Some a ->
+ eval_exprlist ge sp e m le al vl ->
+ eval_expr ge sp e m le a1 v1 ->
+ eval_expr ge sp e m le a2 v2 ->
+ eval_condition cond vl m = Some b ->
+ exists v,
+ eval_expr ge sp e m le a v
+ /\ Val.lessdef (Val.select (Some b) v1 v2 ty) v.
+Proof.
+ unfold select; intros.
+ destruct (match ty with Tint | Tlong | Tfloat | Tsingle => true | _ => false end); inv H.
+ rewrite <- H3; TrivialExists.
+Qed.
+
+(** Addressing modes *)
+
+Theorem eval_addressing:
+ forall le chunk a v b ofs,
+ eval_expr ge sp e m le a v ->
+ v = Vptr b ofs ->
+ match addressing chunk a with (mode, args) =>
+ exists vl,
+ eval_exprlist ge sp e m le args vl /\
+ eval_addressing ge sp mode vl = Some v
+ end.
+Proof.
+ intros until v. unfold addressing; case (addressing_match a); intros; InvEval.
+- econstructor; split. EvalOp. simpl; auto.
+- econstructor; split. EvalOp. simpl; auto.
+- econstructor; split. EvalOp. simpl.
+ destruct v1; try discriminate. rewrite <- H; auto.
+- econstructor; split. EvalOp. simpl. congruence.
+- econstructor; split. EvalOp. simpl. congruence.
+- econstructor; split. EvalOp. simpl. congruence.
+- econstructor; split. EvalOp. simpl. rewrite H0. simpl. rewrite Ptrofs.add_zero; auto.
+Qed.
+
+(** Builtins *)
+
+Theorem eval_builtin_arg:
+ forall a v,
+ eval_expr ge sp e m nil a v ->
+ CminorSel.eval_builtin_arg ge sp e m (builtin_arg a) v.
+Proof.
+ intros until v. unfold builtin_arg; case (builtin_arg_match a); intros; InvEval.
+- constructor.
+- constructor.
+- constructor.
+- constructor.
+- inv H. InvEval. simpl in H6. inv H6. constructor; auto.
+- subst v. repeat constructor; auto.
+- constructor; auto.
+Qed.
+
+(** Platform-specific known builtins *)
+
+Theorem eval_platform_builtin:
+ forall bf al a vl v le,
+ platform_builtin bf al = Some a ->
+ eval_exprlist ge sp e m le al vl ->
+ platform_builtin_sem bf vl = Some v ->
+ exists v', eval_expr ge sp e m le a v' /\ Val.lessdef v v'.
+Proof.
+ intros. discriminate.
+Qed.
+
+End CMCONSTR.
diff --git a/aarch64/Stacklayout.v b/aarch64/Stacklayout.v
new file mode 100644
index 00000000..86ba9f45
--- /dev/null
+++ b/aarch64/Stacklayout.v
@@ -0,0 +1,140 @@
+(* *********************************************************************)
+(* *)
+(* 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. *)
+(* *)
+(* *********************************************************************)
+
+(** Machine- and ABI-dependent layout information for activation records. *)
+
+Require Import Coqlib.
+Require Import AST Memory Separation.
+Require Import Bounds.
+
+Local Open Scope sep_scope.
+
+(** The general shape of activation records is as follows,
+ from bottom (lowest offsets) to top:
+- Space for outgoing arguments to function calls.
+- Back link to parent frame
+- Return address
+- Saved values of callee-save registers used by the function.
+- Local stack slots.
+- Space for the stack-allocated data declared in Cminor.
+
+The stack pointer is kept 16-aligned.
+*)
+
+Definition fe_ofs_arg := 0.
+
+Definition make_env (b: bounds) : frame_env :=
+ let olink := align (4 * b.(bound_outgoing)) 8 in (* back link *)
+ let oretaddr := olink + 8 in (* return address *)
+ let ocs := oretaddr + 8 in (* callee-saves *)
+ let ol := align (size_callee_save_area b ocs) 8 in (* locals *)
+ let ostkdata := align (ol + 4 * b.(bound_local)) 8 in (* stack data *)
+ let sz := align (ostkdata + b.(bound_stack_data)) 16 in
+ {| fe_size := sz;
+ fe_ofs_link := olink;
+ fe_ofs_retaddr := oretaddr;
+ fe_ofs_local := ol;
+ fe_ofs_callee_save := ocs;
+ fe_stack_data := ostkdata;
+ fe_used_callee_save := b.(used_callee_save) |}.
+
+Lemma frame_env_separated:
+ forall b sp m P,
+ let fe := make_env b in
+ m |= range sp 0 (fe_stack_data fe) ** range sp (fe_stack_data fe + bound_stack_data b) (fe_size fe) ** P ->
+ m |= range sp (fe_ofs_local fe) (fe_ofs_local fe + 4 * bound_local b)
+ ** range sp fe_ofs_arg (fe_ofs_arg + 4 * bound_outgoing b)
+ ** range sp (fe_ofs_link fe) (fe_ofs_link fe + size_chunk Mptr)
+ ** range sp (fe_ofs_retaddr fe) (fe_ofs_retaddr fe + size_chunk Mptr)
+ ** range sp (fe_ofs_callee_save fe) (size_callee_save_area b (fe_ofs_callee_save fe))
+ ** P.
+Proof.
+Local Opaque Z.add Z.mul sepconj range.
+ intros; simpl.
+ set (olink := align (4 * b.(bound_outgoing)) 8).
+ set (oretaddr := olink + 8).
+ set (ocs := oretaddr + 8).
+ set (ol := align (size_callee_save_area b ocs) 8).
+ set (ostkdata := align (ol + 4 * b.(bound_local)) 8).
+ change (size_chunk Mptr) with 8.
+ generalize b.(bound_local_pos) b.(bound_outgoing_pos) b.(bound_stack_data_pos); intros.
+ assert (0 <= 4 * b.(bound_outgoing)) by omega.
+ assert (4 * b.(bound_outgoing) <= olink) by (apply align_le; omega).
+ assert (olink + 8 <= oretaddr) by (unfold oretaddr; omega).
+ assert (oretaddr + 8 <= ocs) by (unfold ocs; omega).
+ assert (ocs <= size_callee_save_area b ocs) by (apply size_callee_save_area_incr).
+ assert (size_callee_save_area b ocs <= ol) by (apply align_le; omega).
+ assert (ol + 4 * b.(bound_local) <= ostkdata) by (apply align_le; omega).
+(* Reorder as:
+ outgoing
+ back link
+ retaddr
+ callee-save
+ local *)
+ rewrite sep_swap12.
+ rewrite sep_swap23.
+ rewrite sep_swap34.
+ rewrite sep_swap45.
+(* Apply range_split and range_split2 repeatedly *)
+ unfold fe_ofs_arg.
+ apply range_split_2. fold olink; omega. omega.
+ apply range_split. omega.
+ apply range_split. omega.
+ apply range_split_2. fold ol. omega. omega.
+ apply range_drop_right with ostkdata. omega.
+ eapply sep_drop2. eexact H.
+Qed.
+
+Lemma frame_env_range:
+ forall b,
+ let fe := make_env b in
+ 0 <= fe_stack_data fe /\ fe_stack_data fe + bound_stack_data b <= fe_size fe.
+Proof.
+ intros; simpl.
+ set (olink := align (4 * b.(bound_outgoing)) 8).
+ set (oretaddr := olink + 8).
+ set (ocs := oretaddr + 8).
+ set (ol := align (size_callee_save_area b ocs) 8).
+ set (ostkdata := align (ol + 4 * b.(bound_local)) 8).
+ generalize b.(bound_local_pos) b.(bound_outgoing_pos) b.(bound_stack_data_pos); intros.
+ assert (0 <= 4 * b.(bound_outgoing)) by omega.
+ assert (4 * b.(bound_outgoing) <= olink) by (apply align_le; omega).
+ assert (olink + 8 <= oretaddr) by (unfold oretaddr; omega).
+ assert (oretaddr + 8 <= ocs) by (unfold ocs; omega).
+ assert (ocs <= size_callee_save_area b ocs) by (apply size_callee_save_area_incr).
+ assert (size_callee_save_area b ocs <= ol) by (apply align_le; omega).
+ assert (ol + 4 * b.(bound_local) <= ostkdata) by (apply align_le; omega).
+ split. omega. apply align_le. omega.
+Qed.
+
+Lemma frame_env_aligned:
+ forall b,
+ let fe := make_env b in
+ (8 | fe_ofs_arg)
+ /\ (8 | fe_ofs_local fe)
+ /\ (8 | fe_stack_data fe)
+ /\ (align_chunk Mptr | fe_ofs_link fe)
+ /\ (align_chunk Mptr | fe_ofs_retaddr fe).
+Proof.
+ intros; simpl.
+ set (olink := align (4 * b.(bound_outgoing)) 8).
+ set (oretaddr := olink + 8).
+ set (ocs := oretaddr + 8).
+ set (ol := align (size_callee_save_area b ocs) 8).
+ set (ostkdata := align (ol + 4 * b.(bound_local)) 8).
+ change (align_chunk Mptr) with 8.
+ split. apply Z.divide_0_r.
+ split. apply align_divides; omega.
+ split. apply align_divides; omega.
+ split. apply align_divides; omega.
+ apply Z.divide_add_r. apply align_divides; omega. apply Z.divide_refl.
+Qed.
diff --git a/aarch64/TargetPrinter.ml b/aarch64/TargetPrinter.ml
new file mode 100644
index 00000000..e54673dd
--- /dev/null
+++ b/aarch64/TargetPrinter.ml
@@ -0,0 +1,592 @@
+(* *********************************************************************)
+(* *)
+(* 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. *)
+(* *)
+(* *********************************************************************)
+
+(* Printing AArch64 assembly code in asm syntax *)
+
+open Printf
+open Camlcoq
+open Sections
+open AST
+open Asm
+open AisAnnot
+open PrintAsmaux
+open Fileinfo
+
+(* Recognition of FP numbers that are supported by the fmov #imm instructions:
+ "a normalized binary floating point encoding with 1 sign bit,
+ 4 bits of fraction and a 3-bit exponent"
+*)
+
+let is_immediate_float64 bits =
+ let exp = (Int64.(to_int (shift_right_logical bits 52)) land 0x7FF) - 1023 in
+ let mant = Int64.logand bits 0xF_FFFF_FFFF_FFFFL in
+ exp >= -3 && exp <= 4 && Int64.logand mant 0xF_0000_0000_0000L = mant
+
+let is_immediate_float32 bits =
+ let exp = (Int32.(to_int (shift_right_logical bits 23)) land 0xFF) - 127 in
+ let mant = Int32.logand bits 0x7F_FFFFl in
+ exp >= -3 && exp <= 4 && Int32.logand mant 0x78_0000l = mant
+
+(* Module containing the printing functions *)
+
+module Target : TARGET =
+ struct
+
+(* Basic printing functions *)
+
+ let comment = "//"
+
+ let symbol = elf_symbol
+ let symbol_offset = elf_symbol_offset
+ let label = elf_label
+
+ let print_label oc lbl = label oc (transl_label lbl)
+
+ let intsz oc (sz, n) =
+ match sz with X -> coqint64 oc n | W -> coqint oc n
+
+ let xreg_name = function
+ | X0 -> "x0" | X1 -> "x1" | X2 -> "x2" | X3 -> "x3"
+ | X4 -> "x4" | X5 -> "x5" | X6 -> "x6" | X7 -> "x7"
+ | X8 -> "x8" | X9 -> "x9" | X10 -> "x10" | X11 -> "x11"
+ | X12 -> "x12" | X13 -> "x13" | X14 -> "x14" | X15 -> "x15"
+ | X16 -> "x16" | X17 -> "x17" | X18 -> "x18" | X19 -> "x19"
+ | X20 -> "x20" | X21 -> "x21" | X22 -> "x22" | X23 -> "x23"
+ | X24 -> "x24" | X25 -> "x25" | X26 -> "x26" | X27 -> "x27"
+ | X28 -> "x28" | X29 -> "x29" | X30 -> "x30"
+
+ let wreg_name = function
+ | X0 -> "w0" | X1 -> "w1" | X2 -> "w2" | X3 -> "w3"
+ | X4 -> "w4" | X5 -> "w5" | X6 -> "w6" | X7 -> "w7"
+ | X8 -> "w8" | X9 -> "w9" | X10 -> "w10" | X11 -> "w11"
+ | X12 -> "w12" | X13 -> "w13" | X14 -> "w14" | X15 -> "w15"
+ | X16 -> "w16" | X17 -> "w17" | X18 -> "w18" | X19 -> "w19"
+ | X20 -> "w20" | X21 -> "w21" | X22 -> "w22" | X23 -> "w23"
+ | X24 -> "w24" | X25 -> "w25" | X26 -> "w26" | X27 -> "w27"
+ | X28 -> "w28" | X29 -> "w29" | X30 -> "w30"
+
+ let xreg0_name = function RR0 r -> xreg_name r | XZR -> "xzr"
+ let wreg0_name = function RR0 r -> wreg_name r | XZR -> "wzr"
+
+ let xregsp_name = function RR1 r -> xreg_name r | XSP -> "sp"
+ let wregsp_name = function RR1 r -> wreg_name r | XSP -> "wsp"
+
+ let dreg_name = function
+ | D0 -> "d0" | D1 -> "d1" | D2 -> "d2" | D3 -> "d3"
+ | D4 -> "d4" | D5 -> "d5" | D6 -> "d6" | D7 -> "d7"
+ | D8 -> "d8" | D9 -> "d9" | D10 -> "d10" | D11 -> "d11"
+ | D12 -> "d12" | D13 -> "d13" | D14 -> "d14" | D15 -> "d15"
+ | D16 -> "d16" | D17 -> "d17" | D18 -> "d18" | D19 -> "d19"
+ | D20 -> "d20" | D21 -> "d21" | D22 -> "d22" | D23 -> "d23"
+ | D24 -> "d24" | D25 -> "d25" | D26 -> "d26" | D27 -> "d27"
+ | D28 -> "d28" | D29 -> "d29" | D30 -> "d30" | D31 -> "d31"
+
+ let sreg_name = function
+ | D0 -> "s0" | D1 -> "s1" | D2 -> "s2" | D3 -> "s3"
+ | D4 -> "s4" | D5 -> "s5" | D6 -> "s6" | D7 -> "s7"
+ | D8 -> "s8" | D9 -> "s9" | D10 -> "s10" | D11 -> "s11"
+ | D12 -> "s12" | D13 -> "s13" | D14 -> "s14" | D15 -> "s15"
+ | D16 -> "s16" | D17 -> "s17" | D18 -> "s18" | D19 -> "s19"
+ | D20 -> "s20" | D21 -> "s21" | D22 -> "s22" | D23 -> "s23"
+ | D24 -> "s24" | D25 -> "s25" | D26 -> "s26" | D27 -> "s27"
+ | D28 -> "s28" | D29 -> "s29" | D30 -> "s30" | D31 -> "s31"
+
+ let xreg oc r = output_string oc (xreg_name r)
+ let wreg oc r = output_string oc (wreg_name r)
+ let ireg oc (sz, r) =
+ output_string oc (match sz with X -> xreg_name r | W -> wreg_name r)
+
+ let xreg0 oc r = output_string oc (xreg0_name r)
+ let wreg0 oc r = output_string oc (wreg0_name r)
+ let ireg0 oc (sz, r) =
+ output_string oc (match sz with X -> xreg0_name r | W -> wreg0_name r)
+
+ let xregsp oc r = output_string oc (xregsp_name r)
+ let iregsp oc (sz, r) =
+ output_string oc (match sz with X -> xregsp_name r | W -> wregsp_name r)
+
+ let dreg oc r = output_string oc (dreg_name r)
+ let sreg oc r = output_string oc (sreg_name r)
+ let freg oc (sz, r) =
+ 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
+ | _ -> assert false
+
+ let preg_annot = function
+ | IR r -> xreg_name r
+ | FR r -> dreg_name r
+ | _ -> assert false
+
+(* Names of sections *)
+
+ let name_of_section = function
+ | Section_text -> ".text"
+ | Section_data i | Section_small_data i ->
+ if i then ".data" else common_section ()
+ | Section_const i | Section_small_const i ->
+ if i || (not !Clflags.option_fcommon) then ".section .rodata" else "COMM"
+ | Section_string -> ".section .rodata"
+ | Section_literal -> ".section .rodata"
+ | Section_jumptable -> ".section .rodata"
+ | Section_debug_info _ -> ".section .debug_info,\"\",%progbits"
+ | Section_debug_loc -> ".section .debug_loc,\"\",%progbits"
+ | Section_debug_abbrev -> ".section .debug_abbrev,\"\",%progbits"
+ | Section_debug_line _ -> ".section .debug_line,\"\",%progbits"
+ | Section_debug_ranges -> ".section .debug_ranges,\"\",%progbits"
+ | Section_debug_str -> ".section .debug_str,\"MS\",%progbits,1"
+ | Section_user(s, wr, ex) ->
+ sprintf ".section \"%s\",\"a%s%s\",%%progbits"
+ s (if wr then "w" else "") (if ex then "x" else "")
+ | Section_ais_annotation -> sprintf ".section \"__compcert_ais_annotations\",\"\",@note"
+
+ let section oc sec =
+ fprintf oc " %s\n" (name_of_section sec)
+
+(* Associate labels to floating-point constants and to symbols. *)
+
+ let emit_constants oc lit =
+ if exists_constants () then begin
+ section oc lit;
+ if Hashtbl.length literal64_labels > 0 then
+ begin
+ fprintf oc " .balign 8\n";
+ Hashtbl.iter
+ (fun bf lbl -> fprintf oc "%a: .quad 0x%Lx\n" label lbl bf)
+ literal64_labels
+ end;
+ if Hashtbl.length literal32_labels > 0 then
+ begin
+ fprintf oc " .balign 4\n";
+ Hashtbl.iter
+ (fun bf lbl ->
+ fprintf oc "%a: .long 0x%lx\n" label lbl bf)
+ literal32_labels
+ end;
+ reset_literals ()
+ end
+
+(* Emit .file / .loc debugging directives *)
+
+ let print_file_line oc file line =
+ print_file_line oc comment file line
+
+(* Name of testable condition *)
+
+ let condition_name = function
+ | TCeq -> "eq"
+ | TCne -> "ne"
+ | TChs -> "hs"
+ | TClo -> "lo"
+ | TCmi -> "mi"
+ | TCpl -> "pl"
+ | TChi -> "hi"
+ | TCls -> "ls"
+ | TCge -> "ge"
+ | TClt -> "lt"
+ | TCgt -> "gt"
+ | TCle -> "le"
+
+(* Print an addressing mode *)
+
+ let addressing oc = function
+ | ADimm(base, n) -> fprintf oc "[%a, #%a]" xregsp base coqint64 n
+ | ADreg(base, r) -> fprintf oc "[%a, %a]" xregsp base xreg r
+ | ADlsl(base, r, n) -> fprintf oc "[%a, %a, lsl #%a]" xregsp base xreg r coqint n
+ | ADsxt(base, r, n) -> fprintf oc "[%a, %a, sxtw #%a]" xregsp base wreg r coqint n
+ | ADuxt(base, r, n) -> fprintf oc "[%a, %a, uxtw #%a]" xregsp base wreg r coqint n
+ | ADadr(base, id, ofs) -> fprintf oc "[%a, #:lo12:%a]" xregsp base symbol_offset (id, ofs)
+ | ADpostincr(base, n) -> fprintf oc "[%a], #%a" xregsp base coqint64 n
+
+(* Print a shifted operand *)
+ let shiftop oc = function
+ | SOnone -> ()
+ | SOlsl n -> fprintf oc ", lsl #%a" coqint n
+ | SOlsr n -> fprintf oc ", lsr #%a" coqint n
+ | SOasr n -> fprintf oc ", asr #%a" coqint n
+ | SOror n -> fprintf oc ", ror #%a" coqint n
+
+(* Print a sign- or zero-extended operand *)
+ let extendop oc = function
+ | EOsxtb n -> fprintf oc ", sxtb #%a" coqint n
+ | EOsxth n -> fprintf oc ", sxth #%a" coqint n
+ | EOsxtw n -> fprintf oc ", sxtw #%a" coqint n
+ | EOuxtb n -> fprintf oc ", uxtb #%a" coqint n
+ | EOuxth n -> fprintf oc ", uxth #%a" coqint n
+ | EOuxtw n -> fprintf oc ", uxtw #%a" coqint n
+ | EOuxtx n -> fprintf oc ", uxtx #%a" coqint n
+
+(* Printing of instructions *)
+ let print_instruction oc = function
+ (* Branches *)
+ | Pb lbl ->
+ fprintf oc " b %a\n" print_label lbl
+ | Pbc(c, lbl) ->
+ fprintf oc " b.%s %a\n" (condition_name c) print_label lbl
+ | Pbl(id, sg) ->
+ fprintf oc " bl %a\n" symbol id
+ | Pbs(id, sg) ->
+ fprintf oc " b %a\n" symbol id
+ | Pblr(r, sg) ->
+ fprintf oc " blr %a\n" xreg r
+ | Pbr(r, sg) ->
+ fprintf oc " br %a\n" xreg r
+ | Pret r ->
+ fprintf oc " ret %a\n" xreg r
+ | Pcbnz(sz, r, lbl) ->
+ fprintf oc " cbnz %a, %a\n" ireg (sz, r) print_label lbl
+ | Pcbz(sz, r, lbl) ->
+ fprintf oc " cbz %a, %a\n" ireg (sz, r) print_label lbl
+ | Ptbnz(sz, r, n, lbl) ->
+ fprintf oc " tbnz %a, #%a, %a\n" ireg (sz, r) coqint n print_label lbl
+ | Ptbz(sz, r, n, lbl) ->
+ fprintf oc " tbz %a, #%a, %a\n" ireg (sz, r) coqint n print_label lbl
+ (* Memory loads and stores *)
+ | Pldrw(rd, a) | Pldrw_a(rd, a) ->
+ fprintf oc " ldr %a, %a\n" wreg rd addressing a
+ | Pldrx(rd, a) | Pldrx_a(rd, a) ->
+ fprintf oc " ldr %a, %a\n" xreg rd addressing a
+ | Pldrb(sz, rd, a) ->
+ fprintf oc " ldrb %a, %a\n" wreg rd addressing a
+ | Pldrsb(sz, rd, a) ->
+ fprintf oc " ldrsb %a, %a\n" ireg (sz, rd) addressing a
+ | Pldrh(sz, rd, a) ->
+ fprintf oc " ldrh %a, %a\n" wreg rd addressing a
+ | Pldrsh(sz, rd, a) ->
+ fprintf oc " ldrsh %a, %a\n" ireg (sz, rd) addressing a
+ | Pldrzw(rd, a) ->
+ fprintf oc " ldr %a, %a\n" wreg rd addressing a
+ (* the upper 32 bits of Xrd are set to 0, performing zero-extension *)
+ | Pldrsw(rd, a) ->
+ fprintf oc " ldrsw %a, %a\n" xreg rd addressing a
+ | Pldp(rd1, rd2, a) ->
+ fprintf oc " ldp %a, %a, %a\n" xreg rd1 xreg rd2 addressing a
+ | Pstrw(rs, a) | Pstrw_a(rs, a) ->
+ fprintf oc " str %a, %a\n" wreg rs addressing a
+ | Pstrx(rs, a) | Pstrx_a(rs, a) ->
+ fprintf oc " str %a, %a\n" xreg rs addressing a
+ | Pstrb(rs, a) ->
+ fprintf oc " strb %a, %a\n" wreg rs addressing a
+ | Pstrh(rs, a) ->
+ fprintf oc " strh %a, %a\n" wreg rs addressing a
+ | Pstp(rs1, rs2, a) ->
+ fprintf oc " stp %a, %a, %a\n" xreg rs1 xreg rs2 addressing a
+ (* Integer arithmetic, immediate *)
+ | Paddimm(sz, rd, r1, n) ->
+ fprintf oc " add %a, %a, #%a\n" iregsp (sz, rd) iregsp (sz, r1) intsz (sz, n)
+ | Psubimm(sz, rd, r1, n) ->
+ fprintf oc " sub %a, %a, #%a\n" iregsp (sz, rd) iregsp (sz, r1) intsz (sz, n)
+ | Pcmpimm(sz, r1, n) ->
+ fprintf oc " cmp %a, #%a\n" ireg (sz, r1) intsz (sz, n)
+ | Pcmnimm(sz, r1, n) ->
+ fprintf oc " cmn %a, #%a\n" ireg (sz, r1) intsz (sz, n)
+ (* Move integer register *)
+ | Pmov(rd, r1) ->
+ fprintf oc " mov %a, %a\n" xregsp rd xregsp r1
+ (* Logical, immediate *)
+ | Pandimm(sz, rd, r1, n) ->
+ fprintf oc " and %a, %a, #%a\n" ireg (sz, rd) ireg0 (sz, r1) intsz (sz, n)
+ | Peorimm(sz, rd, r1, n) ->
+ fprintf oc " eor %a, %a, #%a\n" ireg (sz, rd) ireg0 (sz, r1) intsz (sz, n)
+ | Porrimm(sz, rd, r1, n) ->
+ fprintf oc " orr %a, %a, #%a\n" ireg (sz, rd) ireg0 (sz, r1) intsz (sz, n)
+ | Ptstimm(sz, r1, n) ->
+ fprintf oc " tst %a, #%a\n" ireg (sz, r1) intsz (sz, n)
+ (* Move wide immediate *)
+ | Pmovz(sz, rd, n, pos) ->
+ fprintf oc " movz %a, #%d, lsl #%d\n" ireg (sz, rd) (Z.to_int n) (Z.to_int pos)
+ | Pmovn(sz, rd, n, pos) ->
+ fprintf oc " movn %a, #%d, lsl #%d\n" ireg (sz, rd) (Z.to_int n) (Z.to_int pos)
+ | Pmovk(sz, rd, n, pos) ->
+ fprintf oc " movk %a, #%d, lsl #%d\n" ireg (sz, rd) (Z.to_int n) (Z.to_int pos)
+ (* PC-relative addressing *)
+ | Padrp(rd, id, ofs) ->
+ fprintf oc " adrp %a, %a\n" xreg rd symbol_offset (id, ofs)
+ | Paddadr(rd, r1, id, ofs) ->
+ fprintf oc " add %a, %a, #:lo12:%a\n" xreg rd xreg r1 symbol_offset (id, ofs)
+ (* Bit-field operations *)
+ | Psbfiz(sz, rd, r1, r, s) ->
+ fprintf oc " sbfiz %a, %a, %a, %d\n" ireg (sz, rd) ireg (sz, r1) coqint r (Z.to_int s)
+ | Psbfx(sz, rd, r1, r, s) ->
+ fprintf oc " sbfx %a, %a, %a, %d\n" ireg (sz, rd) ireg (sz, r1) coqint r (Z.to_int s)
+ | Pubfiz(sz, rd, r1, r, s) ->
+ fprintf oc " ubfiz %a, %a, %a, %d\n" ireg (sz, rd) ireg (sz, r1) coqint r (Z.to_int s)
+ | Pubfx(sz, rd, r1, r, s) ->
+ fprintf oc " ubfx %a, %a, %a, %d\n" ireg (sz, rd) ireg (sz, r1) coqint r (Z.to_int s)
+ (* Integer arithmetic, shifted register *)
+ | Padd(sz, rd, r1, r2, s) ->
+ fprintf oc " add %a, %a, %a%a\n" ireg (sz, rd) ireg0 (sz, r1) ireg (sz, r2) shiftop s
+ | Psub(sz, rd, r1, r2, s) ->
+ fprintf oc " sub %a, %a, %a%a\n" ireg (sz, rd) ireg0 (sz, r1) ireg (sz, r2) shiftop s
+ | Pcmp(sz, r1, r2, s) ->
+ fprintf oc " cmp %a, %a%a\n" ireg0 (sz, r1) ireg (sz, r2) shiftop s
+ | Pcmn(sz, r1, r2, s) ->
+ fprintf oc " cmn %a, %a%a\n" ireg0 (sz, r1) ireg (sz, r2) shiftop s
+ (* Integer arithmetic, extending register *)
+ | Paddext(rd, r1, r2, x) ->
+ fprintf oc " add %a, %a, %a%a\n" xregsp rd xregsp r1 wreg r2 extendop x
+ | Psubext(rd, r1, r2, x) ->
+ fprintf oc " sub %a, %a, %a%a\n" xregsp rd xregsp r1 wreg r2 extendop x
+ | Pcmpext(r1, r2, x) ->
+ fprintf oc " cmp %a, %a%a\n" xreg r1 wreg r2 extendop x
+ | Pcmnext(r1, r2, x) ->
+ fprintf oc " cmn %a, %a%a\n" xreg r1 wreg r2 extendop x
+ (* Logical, shifted register *)
+ | Pand(sz, rd, r1, r2, s) ->
+ fprintf oc " and %a, %a, %a%a\n" ireg (sz, rd) ireg0 (sz, r1) ireg (sz, r2) shiftop s
+ | Pbic(sz, rd, r1, r2, s) ->
+ fprintf oc " bic %a, %a, %a%a\n" ireg (sz, rd) ireg0 (sz, r1) ireg (sz, r2) shiftop s
+ | Peon(sz, rd, r1, r2, s) ->
+ fprintf oc " eon %a, %a, %a%a\n" ireg (sz, rd) ireg0 (sz, r1) ireg (sz, r2) shiftop s
+ | Peor(sz, rd, r1, r2, s) ->
+ fprintf oc " eor %a, %a, %a%a\n" ireg (sz, rd) ireg0 (sz, r1) ireg (sz, r2) shiftop s
+ | Porr(sz, rd, r1, r2, s) ->
+ fprintf oc " orr %a, %a, %a%a\n" ireg (sz, rd) ireg0 (sz, r1) ireg (sz, r2) shiftop s
+ | Porn(sz, rd, r1, r2, s) ->
+ fprintf oc " orn %a, %a, %a%a\n" ireg (sz, rd) ireg0 (sz, r1) ireg (sz, r2) shiftop s
+ | Ptst(sz, r1, r2, s) ->
+ fprintf oc " tst %a, %a%a\n" ireg0 (sz, r1) ireg (sz, r2) shiftop s
+ (* Variable shifts *)
+ | Pasrv(sz, rd, r1, r2) ->
+ fprintf oc " asr %a, %a, %a\n" ireg (sz, rd) ireg (sz, r1) ireg (sz, r2)
+ | Plslv(sz, rd, r1, r2) ->
+ fprintf oc " lsl %a, %a, %a\n" ireg (sz, rd) ireg (sz, r1) ireg (sz, r2)
+ | Plsrv(sz, rd, r1, r2) ->
+ fprintf oc " lsr %a, %a, %a\n" ireg (sz, rd) ireg (sz, r1) ireg (sz, r2)
+ | Prorv(sz, rd, r1, r2) ->
+ fprintf oc " ror %a, %a, %a\n" ireg (sz, rd) ireg (sz, r1) ireg (sz, r2)
+ (* Bit operations *)
+ | Pcls(sz, rd, r1) ->
+ fprintf oc " cls %a, %a\n" ireg (sz, rd) ireg (sz, r1)
+ | Pclz(sz, rd, r1) ->
+ fprintf oc " clz %a, %a\n" ireg (sz, rd) ireg (sz, r1)
+ | Prev(sz, rd, r1) ->
+ fprintf oc " rev %a, %a\n" ireg (sz, rd) ireg (sz, r1)
+ | Prev16(sz, rd, r1) ->
+ fprintf oc " rev16 %a, %a\n" ireg (sz, rd) ireg (sz, r1)
+ (* Conditional data processing *)
+ | Pcsel(rd, r1, r2, c) ->
+ fprintf oc " csel %a, %a, %a, %s\n" xreg rd xreg r1 xreg r2 (condition_name c)
+ | Pcset(rd, c) ->
+ fprintf oc " cset %a, %s\n" xreg rd (condition_name c)
+ (* Integer multiply/divide *)
+ | Pmadd(sz, rd, r1, r2, r3) ->
+ fprintf oc " madd %a, %a, %a, %a\n" ireg (sz, rd) ireg (sz, r1) ireg (sz, r2) ireg0 (sz, r3)
+ | Pmsub(sz, rd, r1, r2, r3) ->
+ fprintf oc " msub %a, %a, %a, %a\n" ireg (sz, rd) ireg (sz, r1) ireg (sz, r2) ireg0 (sz, r3)
+ | Psmulh(rd, r1, r2) ->
+ fprintf oc " smulh %a, %a, %a\n" xreg rd xreg r1 xreg r2
+ | Pumulh(rd, r1, r2) ->
+ fprintf oc " umulh %a, %a, %a\n" xreg rd xreg r1 xreg r2
+ | Psdiv(sz, rd, r1, r2) ->
+ fprintf oc " sdiv %a, %a, %a\n" ireg (sz, rd) ireg (sz, r1) ireg (sz, r2)
+ | Pudiv(sz, rd, r1, r2) ->
+ fprintf oc " udiv %a, %a, %a\n" ireg (sz, rd) ireg (sz, r1) ireg (sz, r2)
+ (* Floating-point loads and stores *)
+ | Pldrs(rd, a) ->
+ fprintf oc " ldr %a, %a\n" sreg rd addressing a
+ | Pldrd(rd, a) | Pldrd_a(rd, a) ->
+ fprintf oc " ldr %a, %a\n" dreg rd addressing a
+ | Pstrs(rd, a) ->
+ fprintf oc " str %a, %a\n" sreg rd addressing a
+ | Pstrd(rd, a) | Pstrd_a(rd, a) ->
+ fprintf oc " str %a, %a\n" dreg rd addressing a
+ (* Floating-point move *)
+ | Pfmov(rd, r1) ->
+ fprintf oc " fmov %a, %a\n" dreg rd dreg r1
+ | Pfmovimmd(rd, f) ->
+ let d = camlint64_of_coqint (Floats.Float.to_bits f) in
+ if is_immediate_float64 d then
+ fprintf oc " fmov %a, #%.7f\n" dreg rd (Int64.float_of_bits d)
+ else begin
+ let lbl = label_literal64 d in
+ fprintf oc " adrp x16, %a\n" label lbl;
+ fprintf oc " ldr %a, [x16, #:lo12:%a] %s %.18g\n" dreg rd label lbl comment (Int64.float_of_bits d)
+ end
+ | Pfmovimms(rd, f) ->
+ let d = camlint_of_coqint (Floats.Float32.to_bits f) in
+ if is_immediate_float32 d then
+ fprintf oc " fmov %a, #%.7f\n" sreg rd (Int32.float_of_bits d)
+ else begin
+ let lbl = label_literal32 d in
+ fprintf oc " adrp x16, %a\n" label lbl;
+ fprintf oc " ldr %a, [x16, #:lo12:%a] %s %.18g\n" sreg rd label lbl comment (Int32.float_of_bits d)
+ end
+ | Pfmovi(D, rd, r1) ->
+ fprintf oc " fmov %a, %a\n" dreg rd xreg0 r1
+ | Pfmovi(S, rd, r1) ->
+ fprintf oc " fmov %a, %a\n" sreg rd wreg0 r1
+ (* Floating-point conversions *)
+ | Pfcvtds(rd, r1) ->
+ fprintf oc " fcvt %a, %a\n" dreg rd sreg r1
+ | Pfcvtsd(rd, r1) ->
+ fprintf oc " fcvt %a, %a\n" sreg rd dreg r1
+ | Pfcvtzs(isz, fsz, rd, r1) ->
+ fprintf oc " fcvtzs %a, %a\n" ireg (isz, rd) freg (fsz, r1)
+ | Pfcvtzu(isz, fsz, rd, r1) ->
+ fprintf oc " fcvtzu %a, %a\n" ireg (isz, rd) freg (fsz, r1)
+ | Pscvtf(fsz, isz, rd, r1) ->
+ fprintf oc " scvtf %a, %a\n" freg (fsz, rd) ireg (isz, r1)
+ | Pucvtf(fsz, isz, rd, r1) ->
+ fprintf oc " ucvtf %a, %a\n" freg (fsz, rd) ireg (isz, r1)
+ (* Floating-point arithmetic *)
+ | Pfabs(sz, rd, r1) ->
+ fprintf oc " fabs %a, %a\n" freg (sz, rd) freg (sz, r1)
+ | Pfneg(sz, rd, r1) ->
+ fprintf oc " fneg %a, %a\n" freg (sz, rd) freg (sz, r1)
+ | Pfsqrt(sz, rd, r1) ->
+ fprintf oc " fsqrt %a, %a\n" freg (sz, rd) freg (sz, r1)
+ | Pfadd(sz, rd, r1, r2) ->
+ fprintf oc " fadd %a, %a, %a\n" freg (sz, rd) freg (sz, r1) freg (sz, r2)
+ | Pfdiv(sz, rd, r1, r2) ->
+ fprintf oc " fdiv %a, %a, %a\n" freg (sz, rd) freg (sz, r1) freg (sz, r2)
+ | Pfmul(sz, rd, r1, r2) ->
+ fprintf oc " fmul %a, %a, %a\n" freg (sz, rd) freg (sz, r1) freg (sz, r2)
+ | Pfnmul(sz, rd, r1, r2) ->
+ fprintf oc " fnmul %a, %a, %a\n" freg (sz, rd) freg (sz, r1) freg (sz, r2)
+ | Pfsub(sz, rd, r1, r2) ->
+ fprintf oc " fsub %a, %a, %a\n" freg (sz, rd) freg (sz, r1) freg (sz, r2)
+ | Pfmadd(sz, rd, r1, r2, r3) ->
+ fprintf oc " fmadd %a, %a, %a, %a\n" freg (sz, rd) freg (sz, r1) freg (sz, r2) freg (sz, r3)
+ | Pfmsub(sz, rd, r1, r2, r3) ->
+ fprintf oc " fmsub %a, %a, %a, %a\n" freg (sz, rd) freg (sz, r1) freg (sz, r2) freg (sz, r3)
+ | Pfnmadd(sz, rd, r1, r2, r3) ->
+ fprintf oc " fnmadd %a, %a, %a, %a\n" freg (sz, rd) freg (sz, r1) freg (sz, r2) freg (sz, r3)
+ | Pfnmsub(sz, rd, r1, r2, r3) ->
+ fprintf oc " fnmsub %a, %a, %a, %a\n" freg (sz, rd) freg (sz, r1) freg (sz, r2) freg (sz, r3)
+ (* Floating-point comparison *)
+ | Pfcmp(sz, r1, r2) ->
+ fprintf oc " fcmp %a, %a\n" freg (sz, r1) freg (sz, r2)
+ | Pfcmp0(sz, r1) ->
+ fprintf oc " fcmp %a, #0.0\n" freg (sz, r1)
+ (* Floating-point conditional select *)
+ | Pfsel(rd, r1, r2, c) ->
+ fprintf oc " fcsel %a, %a, %a, %s\n" dreg rd dreg r1 dreg r2 (condition_name c)
+ (* No-op *)
+ | Pnop ->
+ fprintf oc " nop\n"
+ (* Pseudo-instructions expanded in Asmexpand *)
+ | Pallocframe(sz, linkofs) -> assert false
+ | Pfreeframe(sz, linkofs) -> assert false
+ | Pcvtx2w rd -> assert false
+ (* Pseudo-instructions not yet expanded *)
+ | Plabel lbl ->
+ fprintf oc "%a:\n" print_label lbl
+ | Ploadsymbol(rd, id) ->
+ fprintf oc " adrp %a, :got:%a\n" xreg rd symbol id;
+ fprintf oc " ldr %a, [%a, #:got_lo12:%a]\n" xreg rd xreg rd symbol id
+ | Pcvtsw2x(rd, r1) ->
+ fprintf oc " sxtw %a, %a\n" xreg rd wreg r1
+ | Pcvtuw2x(rd, r1) ->
+ fprintf oc " uxtw %a, %a\n" xreg rd wreg r1
+ | Pbtbl(r1, tbl) ->
+ let lbl = new_label() in
+ fprintf oc " adr x16, %a\n" label lbl;
+ fprintf oc " add x16, x16, %a, uxtw #2\n" wreg r1;
+ fprintf oc " br x16\n";
+ fprintf oc "%a:" label lbl;
+ List.iter (fun l -> fprintf oc " b %a\n" print_label l) tbl
+ | Pcfi_adjust sz ->
+ cfi_adjust oc (camlint_of_coqint sz)
+ | Pcfi_rel_offset ofs ->
+ cfi_rel_offset oc "lr" (camlint_of_coqint ofs)
+ | Pbuiltin(ef, args, res) ->
+ begin match ef with
+ | EF_annot(kind,txt, targs) ->
+ begin match (P.to_int kind) with
+ | 1 -> let annot = annot_text preg_annot "sp" (camlstring_of_coqstring txt) args in
+ fprintf oc "%s annotation: %S\n" comment annot
+ | 2 -> let lbl = new_label () in
+ fprintf oc "%a:\n" label lbl;
+ add_ais_annot lbl preg_annot "sp" (camlstring_of_coqstring txt) args
+ | _ -> assert false
+ end
+ | EF_debug(kind, txt, targs) ->
+ print_debug_info comment print_file_line preg_annot "sp" oc
+ (P.to_int kind) (extern_atom txt) args
+ | EF_inline_asm(txt, sg, clob) ->
+ fprintf oc "%s begin inline assembly\n\t" comment;
+ print_inline_asm preg_asm oc (camlstring_of_coqstring txt) sg args res;
+ fprintf oc "%s end inline assembly\n" comment
+ | _ ->
+ assert false
+ end
+
+ let get_section_names name =
+ let (text, lit) =
+ match C2C.atom_sections name with
+ | t :: l :: _ -> (t, l)
+ | _ -> (Section_text, Section_literal) in
+ text,lit,Section_jumptable
+
+ let print_align oc alignment =
+ fprintf oc " .balign %d\n" alignment
+
+ let print_jumptable oc jmptbl =
+ let print_tbl oc (lbl, tbl) =
+ fprintf oc "%a:\n" label lbl;
+ List.iter
+ (fun l -> fprintf oc " .long %a - %a\n"
+ print_label l label lbl)
+ tbl in
+ if !jumptables <> [] then
+ begin
+ section oc jmptbl;
+ fprintf oc " .balign 4\n";
+ List.iter (print_tbl oc) !jumptables;
+ jumptables := []
+ end
+
+ let print_fun_info = elf_print_fun_info
+
+ let print_optional_fun_info _ = ()
+
+ let print_var_info = elf_print_var_info
+
+ let print_comm_symb oc sz name align =
+ if C2C.atom_is_static name then
+ fprintf oc " .local %a\n" symbol name;
+ fprintf oc " .comm %a, %s, %d\n"
+ symbol name
+ (Z.to_string sz)
+ align
+
+ let print_instructions oc fn =
+ current_function_sig := fn.fn_sig;
+ List.iter (print_instruction oc) fn.fn_code
+
+(* Data *)
+
+ let address = ".quad"
+
+ let print_prologue oc =
+ if !Clflags.option_g then begin
+ section oc Section_text;
+ end
+
+ let print_epilogue oc =
+ if !Clflags.option_g then begin
+ Debug.compute_gnu_file_enum (fun f -> ignore (print_file oc f));
+ section oc Section_text;
+ end
+
+ let default_falignment = 2
+
+ let cfi_startproc oc = ()
+ let cfi_endproc oc = ()
+
+ end
+
+let sel_target () =
+ (module Target:TARGET)
diff --git a/aarch64/ValueAOp.v b/aarch64/ValueAOp.v
new file mode 100644
index 00000000..e0d98c85
--- /dev/null
+++ b/aarch64/ValueAOp.v
@@ -0,0 +1,319 @@
+(* *********************************************************************)
+(* *)
+(* 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. *)
+(* *)
+(* *********************************************************************)
+
+Require Import Coqlib Compopts.
+Require Import AST Integers Floats Values Memory Globalenvs.
+Require Import Op RTL ValueDomain.
+
+(** Value analysis for AArch64 operators *)
+
+Definition eval_static_shift (s: shift) (v: aval) (n: amount32) : aval :=
+ match s with
+ | Slsl => shl v (I n)
+ | Slsr => shru v (I n)
+ | Sasr => shr v (I n)
+ | Sror => ror v (I n)
+ end.
+
+Definition eval_static_shiftl (s: shift) (v: aval) (n: amount64) : aval :=
+ match s with
+ | Slsl => shll v (I n)
+ | Slsr => shrlu v (I n)
+ | Sasr => shrl v (I n)
+ | Sror => rorl v (I n)
+ end.
+
+Definition eval_static_extend (x: extension) (v: aval) (n: amount64) : aval :=
+ shll (match x with Xsgn32 => longofint v | Xuns32 => longofintu v end) (I n).
+
+Definition eval_static_condition (cond: condition) (vl: list aval): abool :=
+ match cond, vl with
+ | Ccomp c, v1 :: v2 :: nil => cmp_bool c v1 v2
+ | Ccompu c, v1 :: v2 :: nil => cmpu_bool c v1 v2
+ | Ccompimm c n, v1 :: nil => cmp_bool c v1 (I n)
+ | Ccompuimm c n, v1 :: nil => cmpu_bool c v1 (I n)
+ | Ccompshift c s a, v1 :: v2 :: nil => cmp_bool c v1 (eval_static_shift s v2 a)
+ | Ccompushift c s a, v1 :: v2 :: nil => cmpu_bool c v1 (eval_static_shift s v2 a)
+ | Cmaskzero m, v1 :: nil => maskzero v1 m
+ | Cmasknotzero m, v1 :: nil => cnot (maskzero v1 m)
+ | Ccompl c, v1 :: v2 :: nil => cmpl_bool c v1 v2
+ | Ccomplu c, v1 :: v2 :: nil => cmplu_bool c v1 v2
+ | Ccomplimm c n, v1 :: nil => cmpl_bool c v1 (L n)
+ | Ccompluimm c n, v1 :: nil => cmplu_bool c v1 (L n)
+ | Ccomplshift c s a, v1 :: v2 :: nil => cmpl_bool c v1 (eval_static_shiftl s v2 a)
+ | Ccomplushift c s a, v1 :: v2 :: nil => cmplu_bool c v1 (eval_static_shiftl s v2 a)
+ | Cmasklzero m, v1 :: nil => cmpl_bool Ceq (andl v1 (L m)) (L Int64.zero)
+ | Cmasklnotzero m, v1 :: nil => cmpl_bool Cne (andl v1 (L m)) (L Int64.zero)
+ | Ccompf c, v1 :: v2 :: nil => cmpf_bool c v1 v2
+ | Cnotcompf c, v1 :: v2 :: nil => cnot (cmpf_bool c v1 v2)
+ | Ccompfzero c, v1 :: nil => cmpf_bool c v1 (F Float.zero)
+ | Cnotcompfzero c, v1 :: nil => cnot (cmpf_bool c v1 (F Float.zero))
+ | Ccompfs c, v1 :: v2 :: nil => cmpfs_bool c v1 v2
+ | Cnotcompfs c, v1 :: v2 :: nil => cnot (cmpfs_bool c v1 v2)
+ | Ccompfszero c, v1 :: nil => cmpfs_bool c v1 (FS Float32.zero)
+ | Cnotcompfszero c, v1 :: nil => cnot (cmpfs_bool c v1 (FS Float32.zero))
+ | _, _ => Bnone
+ end.
+
+Definition eval_static_addressing (addr: addressing) (vl: list aval): aval :=
+ match addr, vl with
+ | Aindexed n, v1 :: nil => addl v1 (L n)
+ | Aindexed2, v1 :: v2 :: nil => addl v1 v2
+ | Aindexed2shift a, v1 :: v2 :: nil => addl v1 (shll v2 (I a))
+ | Aindexed2ext x a, v1 :: v2 :: nil => addl v1 (eval_static_extend x v2 a)
+ | Aglobal s ofs, nil => Ptr (Gl s ofs)
+ | Ainstack ofs, nil => Ptr (Stk ofs)
+ | _, _ => Vbot
+ end.
+
+Definition eval_static_operation (op: operation) (vl: list aval): aval :=
+ match op, vl with
+ | Omove, v1::nil => v1
+ | Ointconst n, nil => I n
+ | Olongconst n, nil => L n
+ | Ofloatconst n, nil => if propagate_float_constants tt then F n else ntop
+ | Osingleconst n, nil => if propagate_float_constants tt then FS n else ntop
+ | Oaddrsymbol id ofs, nil => Ptr (Gl id ofs)
+ | Oaddrstack ofs, nil => Ptr (Stk ofs)
+
+ | Oshift s a, v1::nil => eval_static_shift s v1 a
+ | Oadd, v1::v2::nil => add v1 v2
+ | Oaddshift s a, v1::v2::nil => add v1 (eval_static_shift s v2 a)
+ | Oaddimm n, v1::nil => add v1 (I n)
+ | Oneg, v1::nil => neg v1
+ | Onegshift s a, v1::nil => neg (eval_static_shift s v1 a)
+ | Osub, v1::v2::nil => sub v1 v2
+ | Osubshift s a, v1::v2::nil => sub v1 (eval_static_shift s v2 a)
+ | Omul, v1::v2::nil => mul v1 v2
+ | Omuladd, v1::v2::v3::nil => add v1 (mul v2 v3)
+ | Omulsub, v1::v2::v3::nil => sub v1 (mul v2 v3)
+ | Odiv, v1::v2::nil => divs v1 v2
+ | Odivu, v1::v2::nil => divu v1 v2
+ | Oand, v1::v2::nil => and v1 v2
+ | Oandshift s a, v1::v2::nil => and v1 (eval_static_shift s v2 a)
+ | Oandimm n, v1::nil => and v1 (I n)
+ | Oor, v1::v2::nil => or v1 v2
+ | Oorshift s a, v1::v2::nil => or v1 (eval_static_shift s v2 a)
+ | Oorimm n, v1::nil => or v1 (I n)
+ | Oxor, v1::v2::nil => xor v1 v2
+ | Oxorshift s a, v1::v2::nil => xor v1 (eval_static_shift s v2 a)
+ | Oxorimm n, v1::nil => xor v1 (I n)
+ | Onot, v1::nil => notint v1
+ | Onotshift s a, v1::nil => notint (eval_static_shift s v1 a)
+ | Obic, v1::v2::nil => and v1 (notint v2)
+ | Obicshift s a, v1::v2::nil => and v1 (notint (eval_static_shift s v2 a))
+ | Oorn, v1::v2::nil => or v1 (notint v2)
+ | Oornshift s a, v1::v2::nil => or v1 (notint (eval_static_shift s v2 a))
+ | Oeqv, v1::v2::nil => xor v1 (notint v2)
+ | Oeqvshift s a, v1::v2::nil => xor v1 (notint (eval_static_shift s v2 a))
+ | Oshl, v1::v2::nil => shl v1 v2
+ | Oshr, v1::v2::nil => shr v1 v2
+ | Oshru, v1::v2::nil => shru v1 v2
+ | Oshrximm n, v1::nil => shrx v1 (I n)
+ | Ozext s, v1::nil => zero_ext s v1
+ | Osext s, v1::nil => sign_ext s v1
+ | Oshlzext s a, v1::nil => shl (zero_ext s v1) (I a)
+ | Oshlsext s a, v1::nil => shl (sign_ext s v1) (I a)
+ | Ozextshr a s, v1::nil => zero_ext s (shru v1 (I a))
+ | Osextshr a s, v1::nil => sign_ext s (shr v1 (I a))
+
+ | Oshiftl s a, v1::nil => eval_static_shiftl s v1 a
+ | Oextend x a, v1::nil => eval_static_extend x v1 a
+ | Omakelong, v1::v2::nil => longofwords v1 v2
+ | Olowlong, v1::nil => loword v1
+ | Ohighlong, v1::nil => hiword v1
+ | Oaddl, v1::v2::nil => addl v1 v2
+ | Oaddlshift s a, v1::v2::nil => addl v1 (eval_static_shiftl s v2 a)
+ | Oaddlext x a, v1::v2::nil => addl v1 (eval_static_extend x v2 a)
+ | Oaddlimm n, v1::nil => addl v1 (L n)
+ | Onegl, v1::nil => negl v1
+ | Oneglshift s a, v1::nil => negl (eval_static_shiftl s v1 a)
+ | Osubl, v1::v2::nil => subl v1 v2
+ | Osublshift s a, v1::v2::nil => subl v1 (eval_static_shiftl s v2 a)
+ | Osublext x a, v1::v2::nil => subl v1 (eval_static_extend x v2 a)
+ | Omull, v1::v2::nil => mull v1 v2
+ | Omulladd, v1::v2::v3::nil => addl v1 (mull v2 v3)
+ | Omullsub, v1::v2::v3::nil => subl v1 (mull v2 v3)
+ | Omullhs, v1::v2::nil => mullhs v1 v2
+ | Omullhu, v1::v2::nil => mullhu v1 v2
+ | Odivl, v1::v2::nil => divls v1 v2
+ | Odivlu, v1::v2::nil => divlu v1 v2
+ | Oandl, v1::v2::nil => andl v1 v2
+ | Oandlshift s a, v1::v2::nil => andl v1 (eval_static_shiftl s v2 a)
+ | Oandlimm n, v1::nil => andl v1 (L n)
+ | Oorl, v1::v2::nil => orl v1 v2
+ | Oorlshift s a, v1::v2::nil => orl v1 (eval_static_shiftl s v2 a)
+ | Oorlimm n, v1::nil => orl v1 (L n)
+ | Oxorl, v1::v2::nil => xorl v1 v2
+ | Oxorlshift s a, v1::v2::nil => xorl v1 (eval_static_shiftl s v2 a)
+ | Oxorlimm n, v1::nil => xorl v1 (L n)
+ | Onotl, v1::nil => notl v1
+ | Onotlshift s a, v1::nil => notl (eval_static_shiftl s v1 a)
+ | Obicl, v1::v2::nil => andl v1 (notl v2)
+ | Obiclshift s a, v1::v2::nil => andl v1 (notl (eval_static_shiftl s v2 a))
+ | Oornl, v1::v2::nil => orl v1 (notl v2)
+ | Oornlshift s a, v1::v2::nil => orl v1 (notl (eval_static_shiftl s v2 a))
+ | Oeqvl, v1::v2::nil => xorl v1 (notl v2)
+ | Oeqvlshift s a, v1::v2::nil => xorl v1 (notl (eval_static_shiftl s v2 a))
+ | Oshll, v1::v2::nil => shll v1 v2
+ | Oshrl, v1::v2::nil => shrl v1 v2
+ | Oshrlu, v1::v2::nil => shrlu v1 v2
+ | Oshrlximm n, v1::nil => shrxl v1 (I n)
+ | Ozextl s, v1::nil => zero_ext_l s v1
+ | Osextl s, v1::nil => sign_ext_l s v1
+ | Oshllzext s a, v1::nil => shll (zero_ext_l s v1) (I a)
+ | Oshllsext s a, v1::nil => shll (sign_ext_l s v1) (I a)
+ | Ozextshrl a s, v1::nil => zero_ext_l s (shrlu v1 (I a))
+ | Osextshrl a s, v1::nil => sign_ext_l s (shrl v1 (I a))
+
+ | Onegf, v1::nil => negf v1
+ | Oabsf, v1::nil => absf v1
+ | Oaddf, v1::v2::nil => addf v1 v2
+ | Osubf, v1::v2::nil => subf v1 v2
+ | Omulf, v1::v2::nil => mulf v1 v2
+ | Odivf, v1::v2::nil => divf v1 v2
+
+ | Onegfs, v1::nil => negfs v1
+ | Oabsfs, v1::nil => absfs v1
+ | Oaddfs, v1::v2::nil => addfs v1 v2
+ | Osubfs, v1::v2::nil => subfs v1 v2
+ | Omulfs, v1::v2::nil => mulfs v1 v2
+ | Odivfs, v1::v2::nil => divfs v1 v2
+
+ | Osingleoffloat, v1::nil => singleoffloat v1
+ | Ofloatofsingle, v1::nil => floatofsingle v1
+ | Ointoffloat, v1::nil => intoffloat v1
+ | Ointuoffloat, v1::nil => intuoffloat v1
+ | Ofloatofint, v1::nil => floatofint v1
+ | Ofloatofintu, v1::nil => floatofintu v1
+ | Ointofsingle, v1::nil => intofsingle v1
+ | Ointuofsingle, v1::nil => intuofsingle v1
+ | Osingleofint, v1::nil => singleofint v1
+ | Osingleofintu, v1::nil => singleofintu v1
+ | Olongoffloat, v1::nil => longoffloat v1
+ | Olonguoffloat, v1::nil => longuoffloat v1
+ | Ofloatoflong, v1::nil => floatoflong v1
+ | Ofloatoflongu, v1::nil => floatoflongu v1
+ | Olongofsingle, v1::nil => longofsingle v1
+ | Olonguofsingle, v1::nil => longuofsingle v1
+ | Osingleoflong, v1::nil => singleoflong v1
+ | Osingleoflongu, v1::nil => singleoflongu v1
+
+ | Ocmp c, _ => of_optbool (eval_static_condition c vl)
+ | Osel c ty, v1::v2::vl => select (eval_static_condition c vl) v1 v2
+
+ | _, _ => Vbot
+ end.
+
+Section SOUNDNESS.
+
+Variable bc: block_classification.
+Variable ge: genv.
+Hypothesis GENV: genv_match bc ge.
+Variable sp: block.
+Hypothesis STACK: bc sp = BCstack.
+
+Ltac InvHyps :=
+ match goal with
+ | [H: None = Some _ |- _ ] => discriminate
+ | [H: Some _ = Some _ |- _] => inv H
+ | [H1: match ?vl with nil => _ | _ :: _ => _ end = Some _ ,
+ H2: list_forall2 _ ?vl _ |- _ ] => inv H2; InvHyps
+ | _ => idtac
+ end.
+
+Lemma eval_static_shift_sound: forall v av s n,
+ vmatch bc v av -> vmatch bc (eval_shift s v n) (eval_static_shift s av n).
+Proof.
+ intros. unfold eval_shift, eval_static_shift; destruct s; auto with va.
+Qed.
+
+Lemma eval_static_shiftl_sound: forall v av s n,
+ vmatch bc v av -> vmatch bc (eval_shiftl s v n) (eval_static_shiftl s av n).
+Proof.
+ intros. unfold eval_shiftl, eval_static_shiftl; destruct s; auto with va.
+Qed.
+
+Lemma eval_static_extend_sound: forall v av x n,
+ vmatch bc v av -> vmatch bc (eval_extend x v n) (eval_static_extend x av n).
+Proof.
+ intros. unfold eval_extend, eval_static_extend; destruct x; auto with va.
+Qed.
+
+Hint Resolve eval_static_shift_sound eval_static_shiftl_sound eval_static_extend_sound: va.
+
+Theorem eval_static_condition_sound:
+ forall cond vargs m aargs,
+ list_forall2 (vmatch bc) vargs aargs ->
+ cmatch (eval_condition cond vargs m) (eval_static_condition cond aargs).
+Proof.
+ intros until aargs; intros VM. inv VM.
+ destruct cond; auto with va.
+ inv H0.
+ destruct cond; simpl; eauto with va.
+ replace (Val.cmp_bool Ceq (Val.and a1 (Vint n)) (Vint Int.zero))
+ with (Val.maskzero_bool a1 n) by (destruct a1; auto).
+ eauto with va.
+ replace (Val.cmp_bool Cne (Val.and a1 (Vint n)) (Vint Int.zero))
+ with (option_map negb (Val.maskzero_bool a1 n)) by (destruct a1; auto).
+ eauto with va.
+ inv H2.
+ destruct cond; simpl; eauto with va.
+ destruct cond; auto with va.
+Qed.
+
+Lemma symbol_address_sound:
+ forall id ofs,
+ vmatch bc (Genv.symbol_address ge id ofs) (Ptr (Gl id ofs)).
+Proof.
+ intros; apply symbol_address_sound; apply GENV.
+Qed.
+
+Lemma symbol_address_sound_2:
+ forall id ofs,
+ vmatch bc (Genv.symbol_address ge id ofs) (Ifptr (Gl id ofs)).
+Proof.
+ intros. unfold Genv.symbol_address. destruct (Genv.find_symbol ge id) as [b|] eqn:F.
+ constructor. constructor. apply GENV; auto.
+ constructor.
+Qed.
+
+Hint Resolve symbol_address_sound symbol_address_sound_2: va.
+
+Theorem eval_static_addressing_sound:
+ forall addr vargs vres aargs,
+ eval_addressing ge (Vptr sp Ptrofs.zero) addr vargs = Some vres ->
+ list_forall2 (vmatch bc) vargs aargs ->
+ vmatch bc vres (eval_static_addressing addr aargs).
+Proof.
+ unfold eval_addressing, eval_static_addressing; intros;
+ destruct addr; InvHyps; eauto with va.
+ rewrite Ptrofs.add_zero_l; eauto with va.
+Qed.
+
+Theorem eval_static_operation_sound:
+ forall op vargs m vres aargs,
+ eval_operation ge (Vptr sp Ptrofs.zero) op vargs m = Some vres ->
+ list_forall2 (vmatch bc) vargs aargs ->
+ vmatch bc vres (eval_static_operation op aargs).
+Proof.
+ unfold eval_operation, eval_static_operation; intros;
+ destruct op; InvHyps; eauto with va.
+ destruct (propagate_float_constants tt); constructor.
+ destruct (propagate_float_constants tt); constructor.
+ rewrite Ptrofs.add_zero_l; eauto with va.
+ apply of_optbool_sound. eapply eval_static_condition_sound; eauto.
+ apply select_sound; eauto using eval_static_condition_sound.
+Qed.
+
+End SOUNDNESS.
+
diff --git a/aarch64/extractionMachdep.v b/aarch64/extractionMachdep.v
new file mode 100644
index 00000000..a447d12f
--- /dev/null
+++ b/aarch64/extractionMachdep.v
@@ -0,0 +1,23 @@
+(* *********************************************************************)
+(* *)
+(* 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. *)
+(* *)
+(* *********************************************************************)
+
+(* Additional extraction directives specific to the AArch64 port *)
+
+Require Archi Asm.
+
+(* Archi *)
+
+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".
diff --git a/backend/Asmgenproof0.v b/backend/Asmgenproof0.v
index 111e435f..3638c465 100644
--- a/backend/Asmgenproof0.v
+++ b/backend/Asmgenproof0.v
@@ -899,30 +899,53 @@ Qed.
(** A variant that supports zero steps of execution *)
-Inductive exec_straight0: code -> regset -> mem ->
- code -> regset -> mem -> Prop :=
- | exec_straight0_none:
- forall c rs m,
- exec_straight0 c rs m c rs m
- | exec_straight0_step:
- forall i c rs1 m1 rs2 m2 c' rs3 m3,
- exec_instr ge fn i rs1 m1 = Next rs2 m2 ->
- rs2#PC = Val.offset_ptr rs1#PC Ptrofs.one ->
- exec_straight0 c rs2 m2 c' rs3 m3 ->
- exec_straight0 (i :: c) rs1 m1 c' rs3 m3.
+Inductive exec_straight_opt: code -> regset -> mem -> code -> regset -> mem -> Prop :=
+ | exec_straight_opt_refl: forall c rs m,
+ exec_straight_opt c rs m c rs m
+ | exec_straight_opt_intro: forall c1 rs1 m1 c2 rs2 m2,
+ exec_straight c1 rs1 m1 c2 rs2 m2 ->
+ exec_straight_opt c1 rs1 m1 c2 rs2 m2.
+
+Lemma exec_straight_opt_left:
+ forall c3 rs3 m3 c1 rs1 m1 c2 rs2 m2,
+ exec_straight c1 rs1 m1 c2 rs2 m2 ->
+ exec_straight_opt c2 rs2 m2 c3 rs3 m3 ->
+ exec_straight c1 rs1 m1 c3 rs3 m3.
+Proof.
+ destruct 2; intros. auto. eapply exec_straight_trans; eauto.
+Qed.
+
+Lemma exec_straight_opt_right:
+ forall c3 rs3 m3 c1 rs1 m1 c2 rs2 m2,
+ exec_straight_opt c1 rs1 m1 c2 rs2 m2 ->
+ exec_straight c2 rs2 m2 c3 rs3 m3 ->
+ exec_straight c1 rs1 m1 c3 rs3 m3.
+Proof.
+ destruct 1; intros. auto. eapply exec_straight_trans; eauto.
+Qed.
-Lemma exec_straight_step':
+Lemma exec_straight_opt_step:
forall i c rs1 m1 rs2 m2 c' rs3 m3,
exec_instr ge fn i rs1 m1 = Next rs2 m2 ->
rs2#PC = Val.offset_ptr rs1#PC Ptrofs.one ->
- exec_straight0 c rs2 m2 c' rs3 m3 ->
+ exec_straight_opt c rs2 m2 c' rs3 m3 ->
exec_straight (i :: c) rs1 m1 c' rs3 m3.
Proof.
- intros. revert i rs1 m1 H H0. revert H1. induction 1; intros.
+ intros. inv H1.
- apply exec_straight_one; auto.
- eapply exec_straight_step; eauto.
Qed.
+Lemma exec_straight_opt_step_opt:
+ forall i c rs1 m1 rs2 m2 c' rs3 m3,
+ exec_instr ge fn i rs1 m1 = Next rs2 m2 ->
+ rs2#PC = Val.offset_ptr rs1#PC Ptrofs.one ->
+ exec_straight_opt c rs2 m2 c' rs3 m3 ->
+ exec_straight_opt (i :: c) rs1 m1 c' rs3 m3.
+Proof.
+ intros. apply exec_straight_opt_intro. eapply exec_straight_opt_step; eauto.
+Qed.
+
End STRAIGHTLINE.
(** * Properties of the Mach call stack *)
diff --git a/backend/Lineartyping.v b/backend/Lineartyping.v
index 55fa7a67..0e3b7c8e 100644
--- a/backend/Lineartyping.v
+++ b/backend/Lineartyping.v
@@ -321,7 +321,7 @@ Local Opaque mreg_type.
+ (* other ops *)
destruct (type_of_operation op) as [ty_args ty_res] eqn:TYOP. InvBooleans.
econstructor; eauto.
- apply wt_setreg; auto. eapply Val.has_subtype; eauto.
+ apply wt_setreg. eapply Val.has_subtype; eauto.
change ty_res with (snd (ty_args, ty_res)). rewrite <- TYOP. eapply type_of_operation_sound; eauto.
red; intros; subst op. simpl in ISMOVE.
destruct args; try discriminate. destruct args; discriminate.
diff --git a/backend/NeedDomain.v b/backend/NeedDomain.v
index b35c90b2..3c2d8e20 100644
--- a/backend/NeedDomain.v
+++ b/backend/NeedDomain.v
@@ -594,7 +594,8 @@ Proof.
Qed.
(** Modular arithmetic operations: add, mul, opposite.
- (But not subtraction because of the pointer - pointer case. *)
+ Also subtraction, but only on 64-bit targets, otherwise
+ the pointer - pointer case does not fit. *)
Definition modarith (x: nval) :=
match x with
@@ -615,6 +616,19 @@ Proof.
- inv H; auto. inv H0; auto. destruct w1; auto.
Qed.
+Lemma sub_sound:
+ forall v1 w1 v2 w2 x,
+ vagree v1 w1 (modarith x) -> vagree v2 w2 (modarith x) ->
+ Archi.ptr64 = true ->
+ vagree (Val.sub v1 v2) (Val.sub w1 w2) x.
+Proof.
+ unfold modarith; intros. destruct x; simpl in *.
+- auto.
+- unfold Val.sub; rewrite H1; InvAgree.
+ apply eqmod_iagree. apply eqmod_sub; apply iagree_eqmod; auto.
+- inv H; auto. inv H0; auto. destruct w1; auto.
+Qed.
+
Remark modarith_idem: forall nv, modarith (modarith nv) = modarith nv.
Proof.
destruct nv; simpl; auto. f_equal; apply complete_mask_idem.
@@ -680,7 +694,7 @@ Definition sign_ext (n: Z) (x: nval) :=
Lemma sign_ext_sound:
forall v w x n,
vagree v w (sign_ext n x) ->
- 0 < n < Int.zwordsize ->
+ 0 < n ->
vagree (Val.sign_ext n v) (Val.sign_ext n w) x.
Proof.
unfold sign_ext; intros. destruct x; simpl in *.
@@ -889,7 +903,8 @@ Lemma default_needs_of_operation_sound:
eval_operation ge (Vptr sp Ptrofs.zero) op args1 m1 = Some v1 ->
vagree_list args1 args2 nil
\/ vagree_list args1 args2 (default nv :: nil)
- \/ vagree_list args1 args2 (default nv :: default nv :: nil) ->
+ \/ vagree_list args1 args2 (default nv :: default nv :: nil)
+ \/ vagree_list args1 args2 (default nv :: default nv :: default nv :: nil) ->
nv <> Nothing ->
exists v2,
eval_operation ge (Vptr sp Ptrofs.zero) op args2 m2 = Some v2
@@ -901,7 +916,8 @@ Proof.
{
destruct H0. auto with na.
destruct H0. inv H0; constructor; auto with na.
- inv H0; constructor; auto with na. inv H8; constructor; auto with na.
+ destruct H0. inv H0. constructor. inv H8; constructor; auto with na.
+ inv H0; constructor; auto with na. inv H8; constructor; auto with na. inv H9; constructor; auto with na.
}
exploit (@eval_operation_inj _ _ _ _ ge ge inject_id).
eassumption. auto. auto. auto.
diff --git a/backend/SelectDivproof.v b/backend/SelectDivproof.v
index f4ff2c86..334bedf6 100644
--- a/backend/SelectDivproof.v
+++ b/backend/SelectDivproof.v
@@ -763,8 +763,8 @@ Lemma eval_divlu_mull:
Proof.
intros. unfold divlu_mull. exploit (divlu_mul_shift x); eauto. intros [A B].
assert (A0: eval_expr ge sp e m le (Eletvar O) (Vlong x)) by (constructor; auto).
- exploit eval_mullhu. eauto. eexact A0. instantiate (1 := Int64.repr M). intros (v1 & A1 & B1).
- exploit eval_shrluimm. eauto. eexact A1. instantiate (1 := Int.repr p). intros (v2 & A2 & B2).
+ exploit eval_mullhu. try apply HELPERS. eexact A0. instantiate (1 := Int64.repr M). intros (v1 & A1 & B1).
+ exploit eval_shrluimm. try apply HELPERS. eexact A1. instantiate (1 := Int.repr p). intros (v2 & A2 & B2).
simpl in B1; inv B1. simpl in B2. replace (Int.ltu (Int.repr p) Int64.iwordsize') with true in B2. inv B2.
rewrite B. assumption.
unfold Int.ltu. rewrite Int.unsigned_repr. rewrite zlt_true; auto. tauto.
@@ -834,17 +834,17 @@ Proof.
intros. unfold divls_mull.
assert (A0: eval_expr ge sp e m le (Eletvar O) (Vlong x)).
{ constructor; auto. }
- exploit eval_mullhs. eauto. eexact A0. instantiate (1 := Int64.repr M). intros (v1 & A1 & B1).
- exploit eval_addl; auto; try apply HELPERS. eexact A1. eexact A0. intros (v2 & A2 & B2).
- exploit eval_shrluimm. eauto. eexact A0. instantiate (1 := Int.repr 63). intros (v3 & A3 & B3).
+ exploit eval_mullhs. try apply HELPERS. eexact A0. instantiate (1 := Int64.repr M). intros (v1 & A1 & B1).
+ exploit eval_addl. try apply HELPERS. eexact A1. eexact A0. intros (v2 & A2 & B2).
+ exploit eval_shrluimm. try apply HELPERS. eexact A0. instantiate (1 := Int.repr 63). intros (v3 & A3 & B3).
set (a4 := if zlt M Int64.half_modulus
then mullhs (Eletvar 0) (Int64.repr M)
else addl (mullhs (Eletvar 0) (Int64.repr M)) (Eletvar 0)).
set (v4 := if zlt M Int64.half_modulus then v1 else v2).
assert (A4: eval_expr ge sp e m le a4 v4).
{ unfold a4, v4; destruct (zlt M Int64.half_modulus); auto. }
- exploit eval_shrlimm. eauto. eexact A4. instantiate (1 := Int.repr p). intros (v5 & A5 & B5).
- exploit eval_addl; auto; try apply HELPERS. eexact A5. eexact A3. intros (v6 & A6 & B6).
+ exploit eval_shrlimm. try apply HELPERS. eexact A4. instantiate (1 := Int.repr p). intros (v5 & A5 & B5).
+ exploit eval_addl. try apply HELPERS. eexact A5. eexact A3. intros (v6 & A6 & B6).
assert (RANGE: forall x, 0 <= x < 64 -> Int.ltu (Int.repr x) Int64.iwordsize' = true).
{ intros. unfold Int.ltu. rewrite Int.unsigned_repr. rewrite zlt_true by tauto. auto.
assert (64 < Int.max_unsigned) by (compute; auto). omega. }
@@ -948,8 +948,7 @@ Proof.
intros until y. unfold divf. destruct (divf_match b); intros.
- unfold divfimm. destruct (Float.exact_inverse n2) as [n2' | ] eqn:EINV.
+ inv H0. inv H4. simpl in H6. inv H6. econstructor; split.
- EvalOp. constructor. eauto. constructor. EvalOp. simpl; eauto. constructor.
- simpl; eauto.
+ repeat (econstructor; eauto).
destruct x; simpl; auto. erewrite Float.div_mul_inverse; eauto.
+ TrivialExists.
- TrivialExists.
@@ -964,8 +963,7 @@ Proof.
intros until y. unfold divfs. destruct (divfs_match b); intros.
- unfold divfsimm. destruct (Float32.exact_inverse n2) as [n2' | ] eqn:EINV.
+ inv H0. inv H4. simpl in H6. inv H6. econstructor; split.
- EvalOp. constructor. eauto. constructor. EvalOp. simpl; eauto. constructor.
- simpl; eauto.
+ repeat (econstructor; eauto).
destruct x; simpl; auto. erewrite Float32.div_mul_inverse; eauto.
+ TrivialExists.
- TrivialExists.
diff --git a/backend/Selectionaux.ml b/backend/Selectionaux.ml
index 4ca7dd21..8acae8f2 100644
--- a/backend/Selectionaux.ml
+++ b/backend/Selectionaux.ml
@@ -68,6 +68,8 @@ let rec cost_expr = function
let fast_cmove ty =
match Configuration.arch, Configuration.model with
+ | "aarch64", _ ->
+ (match ty with Tint | Tlong | Tfloat | Tsingle -> true | _ -> false)
| "arm", _ ->
(match ty with Tint | Tfloat | Tsingle -> true | _ -> false)
| "powerpc", "e5500" ->
diff --git a/backend/Selectionproof.v b/backend/Selectionproof.v
index ee3ed358..8a3aaae6 100644
--- a/backend/Selectionproof.v
+++ b/backend/Selectionproof.v
@@ -1257,8 +1257,8 @@ Proof.
econstructor; eauto.
econstructor; eauto. apply set_var_lessdef; auto.
- (* store *)
- exploit sel_expr_correct. eauto. eauto. eexact H. eauto. eauto. intros [vaddr' [A B]].
- exploit sel_expr_correct. eauto. eauto. eexact H0. eauto. eauto. intros [v' [C D]].
+ exploit sel_expr_correct. try apply LINK. try apply HF. eexact H. eauto. eauto. intros [vaddr' [A B]].
+ exploit sel_expr_correct. try apply LINK. try apply HF. eexact H0. eauto. eauto. intros [v' [C D]].
exploit Mem.storev_extends; eauto. intros [m2' [P Q]].
left; econstructor; split.
eapply eval_store; eauto.
diff --git a/backend/ValueDomain.v b/backend/ValueDomain.v
index fd3bd5ae..c132ce7c 100644
--- a/backend/ValueDomain.v
+++ b/backend/ValueDomain.v
@@ -2093,6 +2093,7 @@ Proof.
Qed.
Definition sign_ext (nbits: Z) (v: aval) :=
+ if zle nbits 0 then Uns (provenance v) 0 else
match v with
| I i => I (Int.sign_ext nbits i)
| Uns p n => if zlt n nbits then Uns p n else sgn p nbits
@@ -2101,20 +2102,39 @@ Definition sign_ext (nbits: Z) (v: aval) :=
end.
Lemma sign_ext_sound:
- forall nbits v x, 0 < nbits -> vmatch v x -> vmatch (Val.sign_ext nbits v) (sign_ext nbits x).
+ forall nbits v x, vmatch v x -> vmatch (Val.sign_ext nbits v) (sign_ext nbits x).
Proof.
assert (DFL: forall p nbits i, 0 < nbits -> vmatch (Vint (Int.sign_ext nbits i)) (sgn p nbits)).
{
intros. apply vmatch_sgn. apply is_sign_ext_sgn; auto with va.
}
- intros. inv H0; simpl; auto with va.
-- destruct (zlt n nbits); eauto with va.
+ intros. unfold sign_ext. destruct (zle nbits 0).
+- destruct v; simpl; auto with va. constructor. omega.
+ rewrite Int.sign_ext_below by auto. red; intros; apply Int.bits_zero.
+- inv H; simpl; auto with va.
++ destruct (zlt n nbits); eauto with va.
constructor; auto. eapply is_sign_ext_uns; eauto with va.
-- destruct (zlt n nbits); auto with va.
-- apply vmatch_sgn. apply is_sign_ext_sgn; auto with va.
++ destruct (zlt n nbits); auto with va.
++ apply vmatch_sgn. apply is_sign_ext_sgn; auto with va.
apply Z.min_case; auto with va.
Qed.
+Definition zero_ext_l (s: Z) := unop_long (Int64.zero_ext s).
+
+Lemma zero_ext_l_sound:
+ forall s v x, vmatch v x -> vmatch (Val.zero_ext_l s v) (zero_ext_l s x).
+Proof.
+ intros s. exact (unop_long_sound (Int64.zero_ext s)).
+Qed.
+
+Definition sign_ext_l (s: Z) := unop_long (Int64.sign_ext s).
+
+Lemma sign_ext_l_sound:
+ forall s v x, vmatch v x -> vmatch (Val.sign_ext_l s v) (sign_ext_l s x).
+Proof.
+ intros s. exact (unop_long_sound (Int64.sign_ext s)).
+Qed.
+
Definition longofint (v: aval) :=
match v with
| I i => L (Int64.repr (Int.signed i))
@@ -4712,6 +4732,7 @@ Hint Resolve cnot_sound symbol_address_sound
negfs_sound absfs_sound
addfs_sound subfs_sound mulfs_sound divfs_sound
zero_ext_sound sign_ext_sound longofint_sound longofintu_sound
+ zero_ext_l_sound sign_ext_l_sound
singleoffloat_sound floatofsingle_sound
intoffloat_sound intuoffloat_sound floatofint_sound floatofintu_sound
intofsingle_sound intuofsingle_sound singleofint_sound singleofintu_sound
diff --git a/configure b/configure
index 9a2db366..dccf6d14 100755
--- a/configure
+++ b/configure
@@ -55,10 +55,12 @@ Supported targets:
x86_64-macosx (x86 64 bits, MacOS X)
rv32-linux (RISC-V 32 bits, Linux)
rv64-linux (RISC-V 64 bits, Linux)
+ aarch64-linux (AArch64, i.e. ARMv8 in 64-bit mode, Linux)
manual (edit configuration file by hand)
For x86 targets, the "x86_32-" prefix can also be written "ia32-" or "i386-".
For x86 targets, the "x86_64-" prefix can also be written "amd64-".
+For AArch64 targets, the "aarch64-" prefix can also be written "arm64-".
For PowerPC targets, the "ppc-" prefix can be refined into:
ppc64- PowerPC 64 bits
@@ -175,6 +177,8 @@ case "$target" in
arch="riscV"; model="32"; endianness="little"; bitsize=32;;
rv64-*)
arch="riscV"; model="64"; endianness="little"; bitsize=64;;
+ aarch64-*|arm64-*)
+ arch="aarch64"; model="default"; endianness="little"; bitsize=64;;
manual)
;;
"")
@@ -428,6 +432,29 @@ if test "$arch" = "riscV"; then
system="linux"
fi
+#
+# AArch64 (ARMv8 64 bits) Target Configuration
+#
+if test "$arch" = "aarch64"; then
+ case "$target" in
+ linux)
+ abi="standard"
+ casm="${toolprefix}gcc"
+ casm_options="-c"
+ cc="${toolprefix}gcc"
+ clinker="${toolprefix}gcc"
+ clinker_options=""
+ cprepro="${toolprefix}gcc"
+ cprepro_options="-std=c99 -U__GNUC__ -E"
+ libmath="-lm"
+ system="linux";;
+ *)
+ echo "Error: invalid eabi/system '$target' for architecture AArch64." 1>&2
+ echo "$usage" 1>&2
+ exit 2;;
+ esac
+fi
+
#
# Finalize Target Configuration
@@ -690,6 +717,8 @@ cat >> Makefile.config <<'EOF'
# ARCH=powerpc
# ARCH=arm
# ARCH=x86
+# ARCH=riscV
+# ARCH=aarch6
ARCH=
# Hardware variant
@@ -703,23 +732,24 @@ ARCH=
# MODEL=armv7m # for ARM
# MODEL=32sse2 # for x86 in 32-bit mode
# MODEL=64 # for x86 in 64-bit mode
+# MODEL=default # for others
MODEL=
# Target ABI
# ABI=eabi # for PowerPC / Linux and other SVR4 or EABI platforms
# ABI=eabi # for ARM
# ABI=hardfloat # for ARM
-# ABI=standard # for x86
+# ABI=standard # for others
ABI=
# Target bit width
-# BITSIZE=64 # for x86 in 64-bit mode
+# BITSIZE=64 # for x86 in 64-bit mode, RiscV in 64-bit mode, AArch64
# BITSIZE=32 # otherwise
BITSIZE=
# Target endianness
# ENDIANNESS=big # for ARM or PowerPC
-# ENDIANNESS=little # for ARM or x86
+# ENDIANNESS=little # for ARM or x86 or RiscV or AArch64
ENDIANNESS=
# Target operating system and development environment
@@ -728,7 +758,7 @@ ENDIANNESS=
# SYSTEM=linux
# SYSTEM=diab
#
-# Possible choices for ARM:
+# Possible choices for ARM, AArch64, RiscV:
# SYSTEM=linux
#
# Possible choices for x86:
diff --git a/cparser/Machine.ml b/cparser/Machine.ml
index 089f2483..97bedb3b 100644
--- a/cparser/Machine.ml
+++ b/cparser/Machine.ml
@@ -237,6 +237,11 @@ let rv64 =
struct_passing_style = SP_ref_callee; (* Wrong *)
struct_return_style = SR_ref } (* to check *)
+let aarch64 =
+ { i32lpll64 with name = "aarch64";
+ struct_passing_style = SP_ref_callee; (* Wrong *)
+ struct_return_style = SR_ref } (* Wrong *)
+
(* Add GCC extensions re: sizeof and alignof *)
let gcc_extensions c =
diff --git a/cparser/Machine.mli b/cparser/Machine.mli
index 8971e2a3..ca7de17b 100644
--- a/cparser/Machine.mli
+++ b/cparser/Machine.mli
@@ -86,6 +86,7 @@ val arm_littleendian : t
val arm_bigendian : t
val rv32 : t
val rv64 : t
+val aarch64 : t
val gcc_extensions : t -> t
val compcert_interpreter : t -> t
diff --git a/driver/Configuration.ml b/driver/Configuration.ml
index 68531701..2188acf0 100644
--- a/driver/Configuration.ml
+++ b/driver/Configuration.ml
@@ -123,7 +123,7 @@ let get_bool_config key =
let arch =
match get_config_string "arch" with
- | "powerpc"|"arm"|"x86"|"riscV" as a -> a
+ | "powerpc"|"arm"|"x86"|"riscV"|"aarch64" as a -> a
| v -> bad_config "arch" [v]
let model = get_config_string "model"
let abi = get_config_string "abi"
diff --git a/driver/Frontend.ml b/driver/Frontend.ml
index bfb3542b..74791247 100644
--- a/driver/Frontend.ml
+++ b/driver/Frontend.ml
@@ -116,6 +116,7 @@ let init () =
| "riscV" -> if Configuration.model = "64"
then Machine.rv64
else Machine.rv32
+ | "aarch64" -> Machine.aarch64
| _ -> assert false
end;
Env.set_builtins C2C.builtins;
diff --git a/lib/Integers.v b/lib/Integers.v
index 066e6b04..3b6c35eb 100644
--- a/lib/Integers.v
+++ b/lib/Integers.v
@@ -2689,42 +2689,93 @@ Proof.
rewrite <- (sign_ext_zero_ext n y H). congruence.
Qed.
-Theorem zero_ext_shru_shl:
+Theorem shru_shl:
+ forall x y z, ltu y iwordsize = true -> ltu z iwordsize = true ->
+ shru (shl x y) z =
+ if ltu z y then shl (zero_ext (zwordsize - unsigned y) x) (sub y z)
+ else zero_ext (zwordsize - unsigned z) (shru x (sub z y)).
+Proof.
+ intros. apply ltu_iwordsize_inv in H; apply ltu_iwordsize_inv in H0.
+ unfold ltu. set (Y := unsigned y) in *; set (Z := unsigned z) in *.
+ apply same_bits_eq; intros. rewrite bits_shru by auto. fold Z.
+ destruct (zlt Z Y).
+- assert (A: unsigned (sub y z) = Y - Z).
+ { apply unsigned_repr. generalize wordsize_max_unsigned; omega. }
+ symmetry; rewrite bits_shl, A by omega.
+ destruct (zlt (i + Z) zwordsize).
++ rewrite bits_shl by omega. fold Y.
+ destruct (zlt i (Y - Z)); [rewrite zlt_true by omega|rewrite zlt_false by omega]; auto.
+ rewrite bits_zero_ext by omega. rewrite zlt_true by omega. f_equal; omega.
++ rewrite bits_zero_ext by omega. rewrite ! zlt_false by omega. auto.
+- assert (A: unsigned (sub z y) = Z - Y).
+ { apply unsigned_repr. generalize wordsize_max_unsigned; omega. }
+ rewrite bits_zero_ext, bits_shru, A by omega.
+ destruct (zlt (i + Z) zwordsize); [rewrite zlt_true by omega|rewrite zlt_false by omega]; auto.
+ rewrite bits_shl by omega. fold Y.
+ destruct (zlt (i + Z) Y).
++ rewrite zlt_false by omega. auto.
++ rewrite zlt_true by omega. f_equal; omega.
+Qed.
+
+Corollary zero_ext_shru_shl:
forall n x,
0 < n < zwordsize ->
let y := repr (zwordsize - n) in
zero_ext n x = shru (shl x y) y.
Proof.
intros.
- assert (unsigned y = zwordsize - n).
- unfold y. apply unsigned_repr. generalize wordsize_max_unsigned. omega.
- apply same_bits_eq; intros.
- rewrite bits_zero_ext.
- rewrite bits_shru; auto.
- destruct (zlt i n).
- rewrite zlt_true. rewrite bits_shl. rewrite zlt_false. f_equal. omega.
- omega. omega. omega.
- rewrite zlt_false. auto. omega.
- omega.
-Qed.
-
-Theorem sign_ext_shr_shl:
+ assert (A: unsigned y = zwordsize - n).
+ { unfold y. apply unsigned_repr. generalize wordsize_max_unsigned. omega. }
+ assert (B: ltu y iwordsize = true).
+ { unfold ltu; rewrite A, unsigned_repr_wordsize. apply zlt_true; omega. }
+ rewrite shru_shl by auto. unfold ltu; rewrite zlt_false by omega.
+ rewrite sub_idem, shru_zero. f_equal. rewrite A; omega.
+Qed.
+
+Theorem shr_shl:
+ forall x y z, ltu y iwordsize = true -> ltu z iwordsize = true ->
+ shr (shl x y) z =
+ if ltu z y then shl (sign_ext (zwordsize - unsigned y) x) (sub y z)
+ else sign_ext (zwordsize - unsigned z) (shr x (sub z y)).
+Proof.
+ intros. apply ltu_iwordsize_inv in H; apply ltu_iwordsize_inv in H0.
+ unfold ltu. set (Y := unsigned y) in *; set (Z := unsigned z) in *.
+ apply same_bits_eq; intros. rewrite bits_shr by auto. fold Z.
+ rewrite bits_shl by (destruct (zlt (i + Z) zwordsize); omega). fold Y.
+ destruct (zlt Z Y).
+- assert (A: unsigned (sub y z) = Y - Z).
+ { apply unsigned_repr. generalize wordsize_max_unsigned; omega. }
+ rewrite bits_shl, A by omega.
+ destruct (zlt i (Y - Z)).
++ apply zlt_true. destruct (zlt (i + Z) zwordsize); omega.
++ rewrite zlt_false by (destruct (zlt (i + Z) zwordsize); omega).
+ rewrite bits_sign_ext by omega. f_equal.
+ destruct (zlt (i + Z) zwordsize).
+ rewrite zlt_true by omega. omega.
+ rewrite zlt_false by omega. omega.
+- assert (A: unsigned (sub z y) = Z - Y).
+ { apply unsigned_repr. generalize wordsize_max_unsigned; omega. }
+ rewrite bits_sign_ext by omega.
+ rewrite bits_shr by (destruct (zlt i (zwordsize - Z)); omega).
+ rewrite A. rewrite zlt_false by (destruct (zlt (i + Z) zwordsize); omega).
+ f_equal. destruct (zlt i (zwordsize - Z)).
++ rewrite ! zlt_true by omega. omega.
++ rewrite ! zlt_false by omega. rewrite zlt_true by omega. omega.
+Qed.
+
+Corollary sign_ext_shr_shl:
forall n x,
0 < n < zwordsize ->
let y := repr (zwordsize - n) in
sign_ext n x = shr (shl x y) y.
Proof.
intros.
- assert (unsigned y = zwordsize - n).
- unfold y. apply unsigned_repr. generalize wordsize_max_unsigned. omega.
- apply same_bits_eq; intros.
- rewrite bits_sign_ext.
- rewrite bits_shr; auto.
- destruct (zlt i n).
- rewrite zlt_true. rewrite bits_shl. rewrite zlt_false. f_equal. omega.
- omega. omega. omega.
- rewrite zlt_false. rewrite bits_shl. rewrite zlt_false. f_equal. omega.
- omega. omega. omega. omega.
+ assert (A: unsigned y = zwordsize - n).
+ { unfold y. apply unsigned_repr. generalize wordsize_max_unsigned. omega. }
+ assert (B: ltu y iwordsize = true).
+ { unfold ltu; rewrite A, unsigned_repr_wordsize. apply zlt_true; omega. }
+ rewrite shr_shl by auto. unfold ltu; rewrite zlt_false by omega.
+ rewrite sub_idem, shr_zero. f_equal. rewrite A; omega.
Qed.
(** [zero_ext n x] is the unique integer congruent to [x] modulo [2^n]
@@ -3643,6 +3694,67 @@ Proof.
unfold shr, shr'; rewrite <- A; auto.
Qed.
+Theorem shru'_shl':
+ forall x y z, Int.ltu y iwordsize' = true -> Int.ltu z iwordsize' = true ->
+ shru' (shl' x y) z =
+ if Int.ltu z y then shl' (zero_ext (zwordsize - Int.unsigned y) x) (Int.sub y z)
+ else zero_ext (zwordsize - Int.unsigned z) (shru' x (Int.sub z y)).
+Proof.
+ intros. apply Int.ltu_inv in H; apply Int.ltu_inv in H0.
+ change (Int.unsigned iwordsize') with zwordsize in *.
+ unfold Int.ltu. set (Y := Int.unsigned y) in *; set (Z := Int.unsigned z) in *.
+ apply same_bits_eq; intros. rewrite bits_shru' by auto. fold Z.
+ destruct (zlt Z Y).
+- assert (A: Int.unsigned (Int.sub y z) = Y - Z).
+ { apply Int.unsigned_repr. assert (zwordsize < Int.max_unsigned) by reflexivity. omega. }
+ symmetry; rewrite bits_shl', A by omega.
+ destruct (zlt (i + Z) zwordsize).
++ rewrite bits_shl' by omega. fold Y.
+ destruct (zlt i (Y - Z)); [rewrite zlt_true by omega|rewrite zlt_false by omega]; auto.
+ rewrite bits_zero_ext by omega. rewrite zlt_true by omega. f_equal; omega.
++ rewrite bits_zero_ext by omega. rewrite ! zlt_false by omega. auto.
+- assert (A: Int.unsigned (Int.sub z y) = Z - Y).
+ { apply Int.unsigned_repr. assert (zwordsize < Int.max_unsigned) by reflexivity. omega. }
+ rewrite bits_zero_ext, bits_shru', A by omega.
+ destruct (zlt (i + Z) zwordsize); [rewrite zlt_true by omega|rewrite zlt_false by omega]; auto.
+ rewrite bits_shl' by omega. fold Y.
+ destruct (zlt (i + Z) Y).
++ rewrite zlt_false by omega. auto.
++ rewrite zlt_true by omega. f_equal; omega.
+Qed.
+
+Theorem shr'_shl':
+ forall x y z, Int.ltu y iwordsize' = true -> Int.ltu z iwordsize' = true ->
+ shr' (shl' x y) z =
+ if Int.ltu z y then shl' (sign_ext (zwordsize - Int.unsigned y) x) (Int.sub y z)
+ else sign_ext (zwordsize - Int.unsigned z) (shr' x (Int.sub z y)).
+Proof.
+ intros. apply Int.ltu_inv in H; apply Int.ltu_inv in H0.
+ change (Int.unsigned iwordsize') with zwordsize in *.
+ unfold Int.ltu. set (Y := Int.unsigned y) in *; set (Z := Int.unsigned z) in *.
+ apply same_bits_eq; intros. rewrite bits_shr' by auto. fold Z.
+ rewrite bits_shl' by (destruct (zlt (i + Z) zwordsize); omega). fold Y.
+ destruct (zlt Z Y).
+- assert (A: Int.unsigned (Int.sub y z) = Y - Z).
+ { apply Int.unsigned_repr. assert (zwordsize < Int.max_unsigned) by reflexivity. omega. }
+ rewrite bits_shl', A by omega.
+ destruct (zlt i (Y - Z)).
++ apply zlt_true. destruct (zlt (i + Z) zwordsize); omega.
++ rewrite zlt_false by (destruct (zlt (i + Z) zwordsize); omega).
+ rewrite bits_sign_ext by omega. f_equal.
+ destruct (zlt (i + Z) zwordsize).
+ rewrite zlt_true by omega. omega.
+ rewrite zlt_false by omega. omega.
+- assert (A: Int.unsigned (Int.sub z y) = Z - Y).
+ { apply Int.unsigned_repr. assert (zwordsize < Int.max_unsigned) by reflexivity. omega. }
+ rewrite bits_sign_ext by omega.
+ rewrite bits_shr' by (destruct (zlt i (zwordsize - Z)); omega).
+ rewrite A. rewrite zlt_false by (destruct (zlt (i + Z) zwordsize); omega).
+ f_equal. destruct (zlt i (zwordsize - Z)).
++ rewrite ! zlt_true by omega. omega.
++ rewrite ! zlt_false by omega. rewrite zlt_true by omega. omega.
+Qed.
+
Lemma shl'_zero_ext:
forall n m x, 0 <= n ->
shl' (zero_ext n x) m = zero_ext (n + Int.unsigned m) (shl' x m).
diff --git a/riscV/Asmgenproof1.v b/riscV/Asmgenproof1.v
index 98d5bd33..b4d6b831 100644
--- a/riscV/Asmgenproof1.v
+++ b/riscV/Asmgenproof1.v
@@ -400,22 +400,6 @@ Ltac ArgsInv :=
| [ H: freg_of _ = OK _ |- _ ] => simpl in *; rewrite (freg_of_eq _ _ H) in *
end).
-Inductive exec_straight_opt: code -> regset -> mem -> code -> regset -> mem -> Prop :=
- | exec_straight_opt_refl: forall c rs m,
- exec_straight_opt c rs m c rs m
- | exec_straight_opt_intro: forall c1 rs1 m1 c2 rs2 m2,
- exec_straight ge fn c1 rs1 m1 c2 rs2 m2 ->
- exec_straight_opt c1 rs1 m1 c2 rs2 m2.
-
-Remark exec_straight_opt_right:
- forall c3 rs3 m3 c1 rs1 m1 c2 rs2 m2,
- exec_straight_opt c1 rs1 m1 c2 rs2 m2 ->
- exec_straight ge fn c2 rs2 m2 c3 rs3 m3 ->
- exec_straight ge fn c1 rs1 m1 c3 rs3 m3.
-Proof.
- destruct 1; intros. auto. eapply exec_straight_trans; eauto.
-Qed.
-
Lemma transl_cbranch_correct_1:
forall cond args lbl k c m ms b sp rs m',
transl_cbranch cond args lbl k = OK c ->
diff --git a/runtime/Makefile b/runtime/Makefile
index 8fe00934..6777995d 100644
--- a/runtime/Makefile
+++ b/runtime/Makefile
@@ -22,6 +22,8 @@ ifeq ($(ARCH),x86_64)
OBJS=i64_dtou.o i64_utod.o i64_utof.o vararg.o
else ifeq ($(ARCH),powerpc64)
OBJS=i64_dtou.o i64_stof.o i64_utod.o i64_utof.o vararg.o
+else ifeq ($(ARCH),aarch64)
+OBJS=vararg.o
else
OBJS=i64_dtos.o i64_dtou.o i64_sar.o i64_sdiv.o i64_shl.o \
i64_shr.o i64_smod.o i64_stod.o i64_stof.o \
diff --git a/runtime/aarch64/sysdeps.h b/runtime/aarch64/sysdeps.h
new file mode 100644
index 00000000..0cee9ae3
--- /dev/null
+++ b/runtime/aarch64/sysdeps.h
@@ -0,0 +1,45 @@
+// *****************************************************************
+//
+// The Compcert verified compiler
+//
+// Xavier Leroy, Collège de France and INRIA Paris
+//
+// Copyright (c) Institut National de Recherche en Informatique et
+// en Automatique.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+// * Neither the name of the <organization> nor the
+// names of its contributors may be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT
+// HOLDER> BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// *********************************************************************
+
+// System dependencies
+
+#define FUNCTION(f) \
+ .text; \
+ .balign 16; \
+ .globl f; \
+f:
+
+#define ENDFUNCTION(f) \
+ .type f, @function; .size f, . - f
+
diff --git a/runtime/aarch64/vararg.S b/runtime/aarch64/vararg.S
new file mode 100644
index 00000000..b7347d65
--- /dev/null
+++ b/runtime/aarch64/vararg.S
@@ -0,0 +1,109 @@
+// *****************************************************************
+//
+// The Compcert verified compiler
+//
+// Xavier Leroy, Collège de France and INRIA Paris
+//
+// Copyright (c) Institut National de Recherche en Informatique et
+// en Automatique.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+// * Neither the name of the <organization> nor the
+// names of its contributors may be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT
+// HOLDER> BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// *********************************************************************
+
+// Helper functions for variadic functions <stdarg.h>. AArch64 version.
+
+#include "sysdeps.h"
+
+// typedef struct __va_list {
+// void *__stack; // next stack parameter
+// void *__gr_top; // top of the save area for int regs
+// void *__vr_top; // top of the save area for float regs
+// int__gr_offs; // offset from gr_top to next int reg
+// int__vr_offs; // offset from gr_top to next FP reg
+// }
+// typedef struct __va_list va_list; // struct passed by reference
+// unsigned int __compcert_va_int32(va_list * ap);
+// unsigned long long __compcert_va_int64(va_list * ap);
+// double __compcert_va_float64(va_list * ap);
+
+FUNCTION(__compcert_va_int32)
+ ldr w1, [x0, #24] // w1 = gr_offs
+ cbz w1, 1f
+ // gr_offs is not zero: load from int save area and update gr_offs
+ ldr x2, [x0, #8] // x2 = gr_top
+ ldr w2, [x2, w1, sxtw] // w2 = the next integer
+ add w1, w1, #8
+ str w1, [x0, #24] // update gr_offs
+ mov w0, w2
+ ret
+ // gr_offs is zero: load from stack save area and update stack pointer
+1: ldr x1, [x0, #0] // x1 = stack
+ ldr w2, [x1, #0] // w2 = the next integer
+ add x1, x1, #8
+ str x1, [x0, #0] // update stack
+ mov w0, w2
+ ret
+ENDFUNCTION(__compcert_va_int32)
+
+FUNCTION(__compcert_va_int64)
+ ldr w1, [x0, #24] // w1 = gr_offs
+ cbz w1, 1f
+ // gr_offs is not zero: load from int save area and update gr_offs
+ ldr x2, [x0, #8] // x2 = gr_top
+ ldr x2, [x2, w1, sxtw] // w2 = the next long integer
+ add w1, w1, #8
+ str w1, [x0, #24] // update gr_offs
+ mov x0, x2
+ ret
+ // gr_offs is zero: load from stack save area and update stack pointer
+1: ldr x1, [x0, #0] // x1 = stack
+ ldr x2, [x1, #0] // w2 = the next long integer
+ add x1, x1, #8
+ str x1, [x0, #0] // update stack
+ mov x0, x2
+ ret
+ENDFUNCTION(__compcert_va_int64)
+
+FUNCTION(__compcert_va_float64)
+ ldr w1, [x0, #28] // w1 = vr_offs
+ cbz w1, 1f
+ // vr_offs is not zero: load from float save area and update vr_offs
+ ldr x2, [x0, #16] // x2 = vr_top
+ ldr d0, [x2, w1, sxtw] // d0 = the next float
+ add w1, w1, #16
+ str w1, [x0, #28] // update vr_offs
+ ret
+ // gr_offs is zero: load from stack save area and update stack pointer
+1: ldr x1, [x0, #0] // x1 = stack
+ ldr d0, [x1, #0] // d0 = the next float
+ add x1, x1, #8
+ str x1, [x0, #0] // update stack
+ ret
+ENDFUNCTION(__compcert_va_float64)
+
+// Right now we pass structs by reference. This is not ABI conformant.
+FUNCTION(__compcert_va_composite)
+ b __compcert_va_int64
+ENDFUNCTION(__compcert_va_composite)
diff --git a/test/regression/Results/builtins-aarch64 b/test/regression/Results/builtins-aarch64
new file mode 100644
index 00000000..c70432d8
--- /dev/null
+++ b/test/regression/Results/builtins-aarch64
@@ -0,0 +1,15 @@
+bswap(12345678) = 78563412
+bswap16(1234) = 3412
+bswap64(123456789abcdef0) = f0debc9a78563412
+clz(12345678) = 3
+clzll(12345678) = 35
+clzll(1234567812345678) = 3
+cls(1234567) = 10
+cls(-9999) = 17
+clsll(1234567) = 42
+clsll(-9999) = 49
+fsqrt(3.141590) = 1.772453
+fmadd(3.141590, 2.718000, 1.414000) = 9.952842
+fmsub(3.141590, 2.718000, 1.414000) = -7.124842
+fnmadd(3.141590, 2.718000, 1.414000) = -9.952842
+fnmsub(3.141590, 2.718000, 1.414000) = 7.124842
diff --git a/test/regression/builtins-aarch64.c b/test/regression/builtins-aarch64.c
new file mode 100644
index 00000000..2cfa2d09
--- /dev/null
+++ b/test/regression/builtins-aarch64.c
@@ -0,0 +1,47 @@
+/* Fun with builtin functions */
+
+#include <stdio.h>
+
+int main(int argc, char ** argv)
+{
+ unsigned int x = 0x12345678;
+ unsigned int y = 0xDEADBEEF;
+ unsigned long long xx = 0x1234567812345678ULL;
+ unsigned long long yy = 0x1234567800000000ULL;
+ unsigned long long zz = 0x123456789ABCDEF0ULL;
+ unsigned z;
+ double a = 3.14159;
+ double b = 2.718;
+ double c = 1.414;
+ unsigned short s = 0x1234;
+ signed int u = 1234567;
+ signed int v = -9999;
+
+ printf("bswap(%x) = %x\n", x, __builtin_bswap(x));
+ printf("bswap16(%x) = %x\n", s, __builtin_bswap16(s));
+ printf("bswap64(%llx) = %llx\n", zz, __builtin_bswap64(zz));
+ printf("clz(%x) = %d\n", x, __builtin_clz(x));
+ printf("clzll(%llx) = %d\n", (unsigned long long) x, __builtin_clzll(x));
+ printf("clzll(%llx) = %d\n", xx, __builtin_clzll(xx));
+ printf("cls(%d) = %d\n", u, __builtin_cls(u));
+ printf("cls(%d) = %d\n", v, __builtin_cls(v));
+ printf("clsll(%lld) = %d\n", (signed long long) u, __builtin_clsll(u));
+ printf("clsll(%lld) = %d\n", (signed long long) v, __builtin_clsll(v));
+
+ printf("fsqrt(%f) = %f\n", a, __builtin_fsqrt(a));
+ printf("fmadd(%f, %f, %f) = %f\n", a, b, c, __builtin_fmadd(a, b, c));
+ printf("fmsub(%f, %f, %f) = %f\n", a, b, c, __builtin_fmsub(a, b, c));
+ printf("fnmadd(%f, %f, %f) = %f\n", a, b, c, __builtin_fnmadd(a, b, c));
+ printf("fnmsub(%f, %f, %f) = %f\n", a, b, c, __builtin_fnmsub(a, b, c));
+
+ /* Make sure that ignoring the result of a builtin
+ doesn't cause an internal error */
+ (void) __builtin_bswap(x);
+ (void) __builtin_fsqrt(a);
+ return 0;
+}
+
+
+
+
+
diff --git a/test/regression/extasm.c b/test/regression/extasm.c
index 83a07a05..297178d1 100644
--- a/test/regression/extasm.c
+++ b/test/regression/extasm.c
@@ -5,14 +5,16 @@ int clobbers(int x, int z)
{
int y;
asm("TEST0 out:%0 in:%1" : "=r"(y) : "r"(x) : "cc"
-#if defined(__x86_64__)
+#if defined(ARCH_x86) && defined(MODEL_64)
, "rax", "rdx", "rbx"
-#elif defined(__i386__)
+#elif defined(ARCH_x86) && !defined(MODEL_64)
, "eax", "edx", "ebx"
-#elif defined(__arm__)
+#elif defined(ARCH_arm)
, "r0", "r1", "r4"
-#elif defined(__PPC__)
+#elif defined(ARCH_powerpc)
, "r0", "r3", "r4", "r31"
+#elif defined(ARCH_aarch64)
+ , "x0", "x1", "x16", "x29", "x30"
#endif
);
return y + z;
@@ -21,7 +23,8 @@ int clobbers(int x, int z)
#if (defined(ARCH_x86) && defined(MODEL_64)) \
|| (defined(ARCH_riscV) && defined(MODEL_64)) \
|| (defined(ARCH_powerpc) && defined(MODEL_ppc64)) \
- || (defined(ARCH_powerpc) && defined(MODEL_e5500))
+ || (defined(ARCH_powerpc) && defined(MODEL_e5500)) \
+ || defined(ARCH_aarch64)
#define SIXTYFOUR
#else
#undef SIXTYFOUR