-
Notifications
You must be signed in to change notification settings - Fork 81
Add an ARMv8-A (AArch64) backend #1541
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
clebreto
wants to merge
61
commits into
jasmin-lang:main
Choose a base branch
from
clebreto:feature/armv8a-distilled
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 58 commits
Commits
Show all changes
61 commits
Select commit
Hold shift + click to select a range
e6a40c3
Add ARMv8-A (AArch64) backend (functional milestone)
clebreto ec87917
armv8a: add 32-bit (W register) instruction forms
clebreto b3df1fd
armv8a: reserve XZR/x18, enforce 16-byte SP alignment, fix SP restore
clebreto cd1f311
armv8a: prove core operation builders (ARMv8AFopn_coreP)
clebreto d6759bf
armv8a: prove params-level operation wrappers (ARMv8AFopnP)
clebreto 4f5e044
armv8a: ground the shift-amount immediate checkers in the Arm ARM
clebreto 598fd86
armv8a: model A64 immediate legality in the argument checkers
clebreto 1745b1d
armv8a: prove the MOVZ/MOVN/MOVK immediate materialization (li)
clebreto 6594122
armv8a: move the SP 16-byte alignment invariant to the stack-alloc or…
clebreto bc2af9c
armv8a: prove the stack-alloc and (most) linearization hypotheses
clebreto f313433
armv8a: complete the linearization hypotheses (armv8a_hliparams)
clebreto 2eee820
armv8a: prove the assembly-generation hypotheses (armv8a_hagparams)
clebreto 681c105
armv8a: prove stack zeroization (armv8a_hszparams)
clebreto 737b366
armv8a: prove lowering correct, complete h_architecture_params
clebreto 983734e
armv8a: accept explicitly masked variable shift amounts
clebreto 767d809
armv8a: test the 32-bit (W register) operations
clebreto 3d6ac4b
armv8a: alphabetize the armv8a entries in _CoqProject
clebreto 3be1aea
armv8a: list the armv8a check category next to the other base archite…
clebreto d627c2f
armv8a: error out instead of claiming safety for the unsupported checker
clebreto 3635bea
armv8a: factor the stack-pointer minimal-alignment bump in stackAlloc
clebreto 8863f9a
armv8a: make the minimal stack-pointer alignment a global option
clebreto 8333ff6
arm, armv8a: share the NZCV flag declarations in arm_common
clebreto cbfb7ce
arm, armv8a: share the condition-code type in arm_common
clebreto a1d9a57
arm, armv8a: share the condition-code evaluation in arm_common
clebreto cd98121
armv8a: remove the variable-shift mnemonics ASRV/LSLV/LSRV/RORV
clebreto 41d3331
armv8a: carry the true per-operand width in pp_aop_args
clebreto ae3e6c1
armv8a: print conditions in place and make pp_asm_arg total
clebreto 9474a95
armv8a: define each instruction's semantics next to its description
clebreto 133614b
armv8a: list the same modules as the other architectures in extraction
clebreto 27e574f
armv8a: define SUBS as ADCS x (invw y) true in the EasyCrypt model
clebreto c63f6fe
armv8a: generate size-suffixed op names, model both sizes in EasyCrypt
clebreto 11669f2
armv8a: make is_doit_asm_op exhaustive, one case per mnemonic
clebreto dd6dc4b
armv8a: fuse multiplications of any width at least the target into MA…
clebreto e69a242
arm, armv8a: extract the shared arm_common module
clebreto 6164586
armv8a: accept armv8a in the cmdliner tools (jasmin2ec, jasmin-ct, ...)
clebreto 642405a
Merge branch 'main' into feature/armv8a
clebreto 15101d8
armv8a: fix ROR in the EasyCrypt model: rotate, not arithmetic shift
clebreto 6d7fcdf
armv8a: rename armv8a_linux_call_conv to armv8a_call_conv
clebreto c4e0d27
armv8a: complete the port to upstream main
clebreto 2ea47ac
armv8a: add the stack-zeroization test categories
clebreto 05545d0
armv8a: test the instruction semantics against the hardware
clebreto 47b94ef
eclib: share the common Arm 32-bit operations in JModel_arm
clebreto ef8ea02
arch: carry the DOIT classification in the instruction descriptors
clebreto 2633f35
attach doit info to the declaration of the instruction
bgregoir 4175961
armv8a: repair the MSUB case of lower_Papp2P
clebreto ef31bc5
armv8a: restrict the shifted variant of instructions to register oper…
clebreto 5d64730
armv8a: forbid ROR on the shifted arithmetic instructions
clebreto 7177f76
arch: cap the default zeroization step by the widest store, not reg_size
clebreto c762306
armv8a: state MVN's register-only argument kinds directly
clebreto f00e297
armv8a: trim the alias-of-V boilerplate from the shift doc blocks
clebreto 8c46ec4
armv8a: distill the instruction model to the lowering-emitted set
clebreto 4d2d6af
armv8a: reject halfword shifts 32/48 on the 32-bit wide moves
clebreto 8d4c50f
armv8a: drop the stale shifted-ROR skip note from the hw-semantics test
clebreto 5be556f
Merge branch 'feature/doit-instr-desc' into feature/armv8a-distilled
clebreto 2a8035c
armv8a: port the immediate-argument conditions to the arch-local inte…
clebreto 270442c
armv8a: declare the DIT classification in the instruction descriptors
clebreto 0e94d6c
Merge branch 'main' of jasmin-lang/jasmin into feature/armv8a-distilled
clebreto bae04d7
armv8a: follow the linearization lload/lstore width generalization
clebreto 1507adc
armv8a: remove a stray duplicate of the add test
clebreto 04af3df
arm: floor the stack-pointer alignment at the architectural 4 bytes
clebreto c78e644
armv8a: use the DOIT/NOT_DOIT constructors directly in the descriptors
clebreto File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,144 @@ | ||
| # ARMv8-A (AArch64) register model and stack-pointer handling — rationale and sources | ||
|
|
||
| This note documents the modeling decisions in the Jasmin AArch64 backend that | ||
| concern the **architecture declaration** (`proofs/compiler/armv8a_decl.v`) and | ||
| the **stack-pointer handling** in the linearization parameters | ||
| (`proofs/compiler/armv8a_params.v`). Each decision departs from a naive "one | ||
| Coq constructor per hardware register" model for a documented architectural or | ||
| ABI reason; the citations below let a reviewer check every claim. | ||
|
|
||
| Primary sources: | ||
|
|
||
| - **Arm ARM** — *Arm Architecture Reference Manual, A-profile*, Arm DDI 0487M.a | ||
| (`DDI0487_M.a.a_a-profile_architecture_reference_manual.pdf`, | ||
| sha256 `c07b1302a3db0c6bc0490808c771d66684ddd5adfb2ef64fd23e6beeb7b22e48`; the | ||
| same edition and hash recorded in `armv8a_isa_docs.json`). Page ids below are | ||
| the manual's own `Sn-NNNN` labels. | ||
| - **AAPCS64** — *Procedure Call Standard for the Arm 64-bit Architecture | ||
| (AArch64)*, Arm IHI 0055F. | ||
| - **Apple** — *Writing ARM64 Code for Apple Platforms*, Apple Developer | ||
| documentation. | ||
|
|
||
| --- | ||
|
|
||
| ## 1. The general-purpose register set | ||
|
|
||
| AArch64 has 31 general-purpose registers `R0..R30`, each addressable as a 64-bit | ||
| `X` register or a 32-bit `W` register, plus a dedicated stack pointer `SP`. | ||
| `R30` is the procedure-call link register. | ||
|
|
||
| > Arm ARM, **B1.2 "Registers in AArch64 Execution state"**, p. B1-203: | ||
| > "31 general-purpose registers, R0 to R30 ... The X30 general-purpose register | ||
| > is used as the procedure call link register. SP — A 64-bit dedicated Stack | ||
| > Pointer register." | ||
|
|
||
| The model keeps `R0..R30` and `RSP`. Two registers that a hardware-faithful | ||
| model might include are deliberately omitted (§2, §3). | ||
|
|
||
| ## 2. The zero register (XZR/WZR) is not modeled | ||
|
|
||
| In an instruction encoding the 5-bit register field value `31` (`0b11111`) does | ||
| **not** name a physical register; its meaning depends on which register accessor | ||
| the instruction uses: | ||
|
|
||
| > Arm ARM, **B1.2**, p. B1-206: | ||
| > "For the general-purpose register X[] accessor, register number 31 accesses | ||
| > the zero register, ZR, which reads as zero and ignores writes." | ||
|
|
||
| The stack pointer is reached through a **separate `SP[]` accessor**, so the same | ||
| field value `31` means `SP` only for the instructions that select it (ADD/SUB in | ||
| their SP forms, MOV-to/from-SP, and loads/stores that allow `SP` as base). | ||
|
|
||
| Consequences for the model: | ||
|
|
||
| - Modeling `ZR` as an allocatable register would be **unsound**: a value written | ||
| to it is discarded and any read returns 0. The register allocator, treating it | ||
| as ordinary storage, produced code such as `mov sp, xzr` (setting SP to 0). | ||
| - We therefore omit it entirely, exactly as the Jasmin RISC-V backend omits the | ||
| hardwired `x0`/`zero`. The handful of operations that genuinely need `ZR` as an | ||
| operand — `CMP` (`SUBS` to `ZR`), `NEG`, `TST`, etc. — are emitted as dedicated | ||
| assembler mnemonics by the printer, never as writes to a `ZR` register. | ||
| - `RSP` is the single encoding-31 register we keep, and it always denotes `SP`. | ||
|
|
||
| ## 3. The platform register (x18) is not modeled | ||
|
|
||
| `x18` is not an architectural special register; it is reserved by the software | ||
| ABI: | ||
|
|
||
| > AAPCS64 (IHI 0055F), *General-purpose registers*: r18 is | ||
| > "The Platform Register, if needed; otherwise a temporary register", and a | ||
| > platform ABI may reserve it. | ||
| > | ||
| > Apple, *Writing ARM64 Code for Apple Platforms*: | ||
| > "The platforms reserve register x18. Don't use this register." | ||
|
|
||
| On Apple platforms, under Windows, and under shadow-call-stack Linux, the OS or | ||
| runtime may overwrite `x18` **asynchronously** (i.e. between two instructions of | ||
| otherwise straight-line user code). Jasmin's register allocator chooses the | ||
| register that holds a function's saved stack pointer by proving the program does | ||
| not clobber it (`get_reg_oracle` in `compiler/src/regalloc.ml`); that analysis | ||
| cannot see writes performed outside the program, so it happily picked `x18` and | ||
| the saved SP was corrupted to 0 at run time. | ||
|
|
||
| Keeping `x18` out of the allocation pool is the only safe choice across these | ||
| platforms. On a platform where `x18` is a plain temporary this merely forgoes | ||
| one scratch register; correctness is unaffected. | ||
|
|
||
| ## 4. The stack pointer must stay 16-byte aligned | ||
|
|
||
| Whenever `SP` is used as the base of a memory access it must be 16-byte aligned. | ||
| This is an **architectural** check (an exception), not just an ABI convention: | ||
|
|
||
| > Arm ARM, **D1.4.10.2 "SP alignment checking"**, p. D1-7135: | ||
| > - rule **RRDMXG**: "When the SP is used as the base address of a calculation, | ||
| > regardless of any offset applied by the instruction, if bits [3:0] of the SP | ||
| > are not 0b0000, there is a misaligned SP." | ||
| > - rule **RTFVSM**: "If SP alignment checking is enabled, then the execution of | ||
| > a load or store using the SP with a misaligned SP generates a synchronous SP | ||
| > Alignment exception on that load or store." | ||
| > - rule **RSTDYJ**: the check is enabled by `SCTLR_EL1.SA` (EL1), | ||
| > `SCTLR_EL1.SA0`/`SCTLR_EL2.SA0` (EL0), etc. | ||
|
|
||
| The check is enabled for EL0 on the platforms we target. The 16-byte alignment | ||
| of `SP` at public interfaces is also mandated by the AAPCS64 (IHI 0055F, *The | ||
| stack*: "SP mod 16 = 0"), which B1.2 (p. B1-203) cross-references. | ||
|
|
||
| Jasmin sizes each stack frame to the alignment of the objects it holds | ||
| (`sao_align`), which for pure 64-bit code is only 8 bytes, so a raw frame size | ||
| need not be a multiple of 16. The backend therefore: | ||
|
|
||
| - rounds every frame allocation/deallocation up to a multiple of 16 | ||
| (`round_up_16`, used by `armv8a_allocate_stack_frame` / | ||
| `armv8a_free_stack_frame`), so nested calls preserve the invariant; and | ||
| - never aligns a re-aligned frame to less than 16 bytes | ||
| (`armv8a_set_up_sp_register`). | ||
|
|
||
| The extra padding lands at the top of the frame and is never accessed. | ||
|
|
||
| ## 5. The stack pointer cannot be an LDR destination | ||
|
|
||
| Because a load writes its result through the general-purpose `X[]` accessor, and | ||
| register number 31 in that accessor is `ZR` (§2), an A64 `LDR` can never write | ||
| `SP`: its destination operand is `<Xt>`, not `<Xt|SP>`. (This differs from | ||
| ARMv7, where R13/SP is an ordinary register that `LDR` can target — which is why | ||
| the shared linearization default, `lloads_imm_dfl`, is fine for the 32-bit Arm | ||
| backend but not here.) | ||
|
|
||
| When the saved stack pointer has been spilled to the stack (the usual case for a | ||
| function that saves callee-saved registers), it must therefore be reloaded into | ||
| a scratch register and then copied to `SP` with a `MOV` (which reaches `SP` via | ||
| the `SP[]` accessor). This is what the backend's custom `armv8a_lloads` does: it | ||
| restores the ordinary saved registers first (relative to the still-live `SP`), | ||
| then loads the saved `SP` into `X17` and issues `MOV SP, X17`. | ||
|
|
||
| --- | ||
|
|
||
| ### Cross-reference to the code | ||
|
|
||
| | Decision | File / definition | Source | | ||
| |---|---|---| | ||
| | Omit `XZR` | `armv8a_decl.v` — `register`, `registers`, `register_to_string` | Arm ARM B1.2, p. B1-206 | | ||
| | Omit `x18` | `armv8a_decl.v` — `register`, `registers`, `armv8a_internal_call_conv` | AAPCS64 IHI 0055F; Apple ABI | | ||
| | Round frames to 16 | `armv8a_params.v` — `round_up_16`, `armv8a_allocate_stack_frame`, `armv8a_free_stack_frame` | Arm ARM D1.4.10.2 (RRDMXG, RTFVSM) | | ||
| | Re-align frames ≥ 16 | `armv8a_params.v` — `armv8a_set_up_sp_register` | Arm ARM D1.4.10.2; AAPCS64 | | ||
| | Restore `SP` via scratch + `MOV` | `armv8a_params.v` — `armv8a_lloads` | Arm ARM B1.2, p. B1-206 | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,63 @@ | ||
| (* ARMv8A architecture full integration *) | ||
| open Arch_decl | ||
|
|
||
| module type Armv8a_input = sig | ||
| val call_conv : (Armv8a_decl.register, Arch_utils.empty, Arch_utils.empty, Arm_common.rflag, Arm_common.condt) calling_convention | ||
| end | ||
|
|
||
| (* Create arch_toIdent for ARMv8A *) | ||
| let atoI armv8a_decl = | ||
| let open Prog in | ||
| let mk_var k t s = | ||
| V.mk s (Reg(k,Direct)) (Conv.ty_of_cty (Type.atype_of_ltype t)) L._dummy [] in | ||
| match Arch_extra.MkAToIdent.mk armv8a_decl mk_var with | ||
| | Utils0.Error e -> | ||
| let e = Conv.error_of_cerror (Printer.pp_err ~debug:true) e in | ||
| raise (Utils.HiError e) | ||
| | Utils0.Ok atoI -> atoI | ||
|
|
||
| module Armv8a (Lowering_params : Armv8a_input) = struct | ||
| module AD = Armv8a_decl | ||
|
|
||
| type reg = AD.register | ||
| type regx = Arch_utils.empty | ||
| type xreg = Arch_utils.empty | ||
| type nonrec rflag = Arm_common.rflag | ||
| type cond = Arm_common.condt | ||
| type asm_op = Armv8a_instr_decl.armv8a_asm_op | ||
| type extra_op = Armv8a_extra.armv8a_extra_op | ||
|
|
||
| let atoI = atoI AD.armv8a_decl | ||
|
|
||
| let asm_e = Armv8a_extra.armv8a_extra atoI | ||
|
|
||
| let aparams = Armv8a_params.armv8a_params atoI | ||
|
|
||
| let known_implicits = ["NF", "_nf_"; "ZF", "_zf_"; "CF", "_cf_"; "VF", "_vf_"] | ||
|
|
||
| let alloc_stack_need_extra _ = false | ||
|
|
||
| let is_ct_asm_op (o : asm_op) = | ||
| match o with | ||
| | Armv8a_instr_decl.ARMv8A_op ((Armv8a_instr_decl.SDIV | Armv8a_instr_decl.UDIV), _) -> false | ||
| | _ -> true | ||
|
|
||
| let is_ct_asm_extra (_o : extra_op) = true | ||
|
|
||
| let not_saved_stack = [] | ||
|
|
||
| let pp_asm = Pp_arm_v8a.print_prog | ||
|
|
||
| let callstyle = Arch_full.ByReg { call = Some Armv8a_decl.R30; return = true } | ||
|
|
||
| (* SP must stay 16-byte aligned: SP alignment checking, Arm ARM | ||
| DDI0487M.a, D1.4.10.2 (see also the AAPCS64 stack constraints). *) | ||
| let sp_min_align = Wsize.U128 | ||
|
|
||
| (* One X-register store; SIMD (NEON) stores would raise this to u128. *) | ||
| let max_store_size = Wsize.U64 | ||
|
|
||
| let internal_call_conv = Armv8a_decl.armv8a_internal_call_conv | ||
|
|
||
| include Lowering_params | ||
| end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.