CensoredUsername / dynasm-rs

A dynasm-like tool for rust.
https://censoredusername.github.io/dynasm-rs/language/index.html
Mozilla Public License 2.0
705 stars 52 forks source link

Aarch64: dynamic registers prevent immediates #82

Closed MarkMcCaskey closed 3 months ago

MarkMcCaskey commented 10 months ago

Hello! Thanks for this crate, it's been pretty useful for me! I noticed that I was unable to use immediate values in aarch64 almost all the time and I think I've narrowed down exactly when they do and do not work.

The simple case of using dynamic registers (either X or W):

dynasm!(a
  ; add X(1), X(1), 1
);

fails with:

error: 'add': instruction format mismatch, expected one of the following forms:
       >>> add Wn, Wm, Wa {, LSL|LSR|ASR #uimm }                                               (#uimm < 32)
       >>> add Xn, Xm, Xa {, LSL|LSR|ASR #uimm }                                               (#uimm < 64)
       >>> add Wn|WSP, Wm|WSP, Wa {, LSL|UXT[BHWX]|SXT[BHWX] #uimm }                      (0 <= #uimm <= 4)
       >>> add Xn|SP, Xm|SP, Wa {, UXT[BHW]|SXT[BHW] { #uimm } }                          (0 <= #uimm <= 4)
       >>> add Xn|SP, Xm|SP, Xa {, LSL|UXTX|SXTX #uimm }                                  (0 <= #uimm <= 4)
       >>> add Wn|WSP, Wm|WSP, #uimm {, LSL #uimm1 }                       (#uimm < 4096, #uimm1 = [0, 12])
       >>> add Xn|SP, Xm|SP, #uimm {, LSL #uimm1 }                         (#uimm < 4096, #uimm1 = [0, 12])
       >>> add Dn, Dm, Da
       >>> add Vn.B16, Vm.B16, Va.B16
       >>> add Vn.B8, Vm.B8, Va.B8
       >>> add Vn.H8, Vm.H8, Va.H8
       >>> add Vn.H4, Vm.H4, Va.H4
       >>> add Vn.S4, Vm.S4, Va.S4
       >>> add Vn.S2, Vm.S2, Va.S2
       >>> add Vn.D2, Vm.D2, Va.D2
   --> src/cpu/jit.rs:623:15
    |
623 |             ; add X(1), X(1), 1
    |               ^^^

and the error message shows

       >>> add Xn|SP, Xm|SP, #uimm {, LSL #uimm1 }                         (#uimm < 4096, #uimm1 = [0, 12])

which implies that it should be accepted.

and the non dynamic form

dynasm!(a
  ; add x1, x1, 1
)

is accepted.

This affects every instruction I've tried (except mov), though some instructions are not affected under certain conditions. For example:

dynasm!(a,
  ; and W(1), W(1), 0xFF
)

fails with

error: 'and': instruction format mismatch, expected one of the following forms:
       >>> and Vn.B16, Vm.B16, Va.B16
       >>> and Vn.B8, Vm.B8, Va.B8
       >>> and Wn|WSP, Wm, #imm                                               (#imm is a logical immediate)
       >>> and Xn|SP, Xm, #imm                                                (#imm is a logical immediate)
       >>> and Wn, Wm, Wa {, LSL|LSR|ASR|ROR #uimm }                                           (#uimm < 32)
       >>> and Xn, Xm, Xa {, LSL|LSR|ASR|ROR #uimm }                                           (#uimm < 64)
   --> src/cpu/jit.rs:623:15
    |
623 |             ; and W(1), W(1), 0xFF
    |               ^^^

but

dynasm!(a,
  ; ands W(1), W(1), 0xFF
)

is accepted.

This is on the currently published 2.0.0 crate. Notably mov is not affected by this, so the work around I've been using is to just use extra registers to move constants into first and do the operations without immediate values.

After I finish up what I'm working on, I'd be interested in trying to fix this if no one else has by then. Thanks!

CensoredUsername commented 10 months ago

Hey! I think the issue here is that you're using the X register family (in which number 31 is xzr), instead of the XSP register family (in which register number 31 is sp).

It is a bit unfortunate that this distinction isn't handled automatically. When using static register codes it's easy to check if either format allows it, but right now with the setup of the register families they really cannot be substituted.

I've thought about just only allowing number 0 up to 30, and only allowing xzr / sp in their literal forms, but that also rules out a bunch of cases where people might want to use those registers dynamically. So for now, you have to specify the family explicitly if you want to use an instruction that can address the stack pointer.

dynasm!(a
  ; add XSP(1), XSP(1), 1
);
CensoredUsername commented 3 months ago

Closing this as it seems to have been solved.