| Age | Commit message (Collapse) | Author |
|
This reverts commit 2f151e76b5dc578026706b31f054d5caf5374b05.
The SP decrement (push) before the call do not match up with
the pops after the call, so registers were restored incorrectly.
Code from:
./miniruby --zjit-call-threshold=1 --zjit-dump-disasm -e 'p Time.new(1992, 9, 23, 23, 0, 0, :std)'
str x11, [sp, #-0x10]!
str x12, [sp, #-0x10]!
stur x7, [sp] # last argument
mov x0, x20
mov x7, x6
mov x6, x5
mov x5, x4
mov x4, x3
mov x3, x2
mov x2, x1
ldur x1, [x29, #-0x20]
mov x16, #0xccfc
movk x16, #0x2e7, lsl #16
movk x16, #1, lsl #32
blr x16
ldr x12, [sp], #0x10 # supposed to match str x12, [sp, #-0x10]!, but got last argument
ldr x11, [sp], #0x10
|
|
ZJIT: Add stack support for CCalls
|
|
|
|
|
|
This commit uses the custom instruction iterator in arm64 / x86_64
instruction splitting. Once we introduce basic blocks to LIR, the
custom iterator will ensure that instructions are added to the correct
place.
|
|
Fix the
```
write(2, "ruby: ZJIT has panicked. More info to follow...\n", 48) = 48
write(2, "\nthread '<unnamed>' panicked at zjit/src/backend/lir.rs:160:17:\nassertion failed: num_bits <= out_num_bits\n", 107) = 107
```
based on
```
#25 0x0000aaaaaae8fb14 in zjit::backend::lir::Opnd::mem (num_bits=64, base=..., disp=0) at zjit/src/backend/lir.rs:160
#26 zjit::backend::arm64::{impl#3}::arm64_split::split_memory_address (asm=<optimized out>,
opnd=<error reading variable: Cannot access memory at address 0x0>) at zjit/src/backend/arm64/mod.rs:260
#27 zjit::backend::arm64::{impl#3}::arm64_split::split_load_operand (asm=<optimized out>, opnd=...) at zjit/src/backend/arm64/mod.rs:273
```
|
|
|
|
|
|
|
|
|
|
|
|
so that it can be easily specified with `--zjit-dump-lir=`.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Previously, when the output register and the base register are the same
in `out = Lea(Mem(out, disp))`, we did
out = disp
out = out + out
Which wasn't the desired `out = out + disp`.
Fixes a SEGV with `--zjit-call-threshold=2` in
`bootstraptest/test_yjit.rb`.
|
|
* The while loop pattern can be rewritten to be more idiomatic, which
also allows the iterator to no longer be mutable.
|
|
|
|
|
|
* ZJIT: Allow testing JIT code on zjit-test
* Resurrect TestingAllocator tests
|
|
|
|
* ZJIT: Fix disasm tests on release build
* Rename string() to hexdump()
|
|
|
|
* ZJIT: Share more code with YJIT in jit.c
* Fix ZJIT references to JIT
|
|
* ZJIT: Allow label generation above 19 bits
* Refactor emit_conditional_jump to use generate_branch
* Make branching functionality generic across Label and CodePtr
* ZJIT: Add > 19 bit jump test and helper function
* Remove an empty line
---------
Co-authored-by: Takashi Kokubun <takashikkbn@gmail.com>
|
|
|
|
|
|
|
|
|
|
|
|
If the LiveRange looks like (idx, idx), we will currently not allocate a
register. This change allocates a register and then immediately
deallocates it.
Fix https://github.com/Shopify/ruby/issues/614
|
|
|
|
|
|
* ZJIT: Remove the need for unwrap() on with_num_bits()
* Fix arm64 tests
* Track the caller of with_num_bits
Co-authored-by: Alan Wu <XrXr@users.noreply.github.com>
---------
Co-authored-by: Alan Wu <XrXr@users.noreply.github.com>
|
|
|
|
Co-authored-by: Takashi Kokubun <takashi.kokubun@shopify.com>
|
|
Previously, ARM64 panicked due to compiled_side_exits() when the memory
displacement got large enough to exceed the 9 bits limit. Usually, we split
these kind of memory operands, but compiled_side_exits() runs after
split.
Using scratch registers, implement `Insn::Store` on ARM such that it can
handle large displacements without split(). Do this for x86 as well, and
remove arch specific code from compiled_side_exits(). We can now run
`TestKeywordArguments`.
Since `Insn::Store` doesn't need splitting now, users enjoy lower
register pressure.
Downside is, using `Assembler::SCRATCH_REG` as a base register is now
sometimes an error, depending on whether `Insn::Store` also needs to
use the register. It seems a fair trade off since `SCRATCH_REG` is
not often used, and we don't put it as a base register anywhere at the
moment.
|
|
Save a couple instructions to load a small negative constant into a
register. In fact MOVN is speced to alias as `mov` in the official
disassembly.
|
|
On the ruby side, this fixes a crash for methods with 39 or more
parameters. We used to miscomp those entry points due to Insn::Lea
picking ADDS which cannot reference SP:
# set method params: 40
mov x0, #0xfee8
movk x0, #0xffff, lsl #16
movk x0, #0xffff, lsl #32
movk x0, #0xffff, lsl #48
adds x0, xzr, x0
Have Lea work for all i32 displacements and avoid involving the split
pass. Previously, direct use of Insn::Lea directly from the user (as
opposed to generated by the split pass for some memory operations)
wasn't split, so being able to handle the whole range in arm64_emit()
was implicitly required. Also, not going through split reduces register
pressure.
|
|
Previously, ZJIT miscompiled the following because of native SP
interference.
def a(n1,n2,n3,n4,n5,n6,n7,n8) = [n8]
a(0,0,0,0,0,0,0, :ok)
Commented problematic disassembly:
; call rb_ary_new_capa
mov x0, #1
mov x16, #0x1278
movk x16, #0x4bc, lsl #16
movk x16, #1, lsl #32
blr x16
; call rb_ary_push
mov x1, x0
str x1, [sp, #-0x10]! ; c_push() from alloc_regs()
mov x0, x1 ; arg0, the array
ldur x1, [sp] ; meant to be arg1=n8, but sp just moved!
mov x16, #0x3968
movk x16, #0x4bc, lsl #16
movk x16, #1, lsl #32
blr x16
Since the frame pointer stays constant in the body of the function,
static offsets based on it don't run the risk of being invalidated by SP
movements.
Pass the registers to preserve through Insn::FrameSetup. This allows ARM
to use STP and waste no gaps between EC, SP, and CFP.
x86 now preserves and restores RBP since we use it as the frame pointer.
Since all arches now have a frame pointer, remove offset based SP
movement in the epilogue and restore registers using the frame pointer.
|
|
Keeping the same name makes re-exporting more concise.
|
|
Previously `no_dead_mov_from_vreg` generated:
0x0: ldur x0, [x0]
0x4: mov x0, x0
0x8: ret
Because of phase ordering. Split couldn't recognize that the no-op mov
because at that point it sees a `VReg`.
|
|
Fix https://github.com/Shopify/ruby/issues/627
|
|
Previously, my buggy optimization would turn `asm.sub(imm, reg)`
into `subs out, reg, imm` since it runs through the addition path which
relies on the commutative property. Don't do that because subtraction
does not commute. Good thing no one seems to use this form.
Also, delete the 2 regs match arm for Add because it's already covered
by the fallback arm -- both split_load_operand() and
split_shifted_immediate() are no-op when the input is a register.
Fixes: 1317377fa74 ("ZJIT: A64: Have add/sub to SP be
single-instruction")
|
|
The raw bytes didn't disassemble to the disassembly, but we missed this
since CI didn't run `make zjit-test` with the disasm feature.
Fixes: 1317377fa74 ("ZJIT: A64: Have add/sub to SP be
single-instruction")
|