fix register logic bug in reset/reuse

This commit is contained in:
Folkert 2023-05-18 16:01:36 +02:00
parent 0ace44ae8c
commit 4af9788b51
No known key found for this signature in database
GPG key ID: 1F17F6FFD112B97C

View file

@ -2691,21 +2691,18 @@ impl<
let element_alignment_symbol = Symbol::DEV_TMP2;
self.load_layout_alignment(Layout::U32, element_alignment_symbol);
let allocation = match reuse {
let allocation = self.debug_symbol("allocation");
match reuse {
None => {
self.allocate_with_refcount(
Symbol::DEV_TMP3,
allocation,
element_width_symbol,
element_alignment_symbol,
);
Symbol::DEV_TMP3
}
Some(reuse) => {
// check for null
self.allocate_with_refcount_if_null(reuse, element_layout);
reuse
self.allocate_with_refcount_if_null(allocation, reuse, element_layout);
}
};
@ -2714,9 +2711,7 @@ impl<
self.build_ptr_write(sym, allocation, value, element_layout);
if allocation == Symbol::DEV_TMP3 {
self.free_symbol(&Symbol::DEV_TMP3);
}
self.free_symbol(&allocation);
}
fn expr_unbox(&mut self, dst: Symbol, ptr: Symbol, element_layout: InLayout<'a>) {
@ -3441,34 +3436,59 @@ impl<
);
}
fn allocate_with_refcount_if_null(&mut self, dst: Symbol, layout: InLayout) {
let reg = self
fn allocate_with_refcount_if_null(&mut self, dst: Symbol, src: Symbol, layout: InLayout) {
let src_reg = self
.storage_manager
.load_to_general_reg(&mut self.buf, &dst);
.load_to_general_reg(&mut self.buf, &src);
// dummy mov that is supposed to move src into dst, and is filled in later because don't know yet which
// register the other branch will pick for dst. We must pass two different registers here
// otherwise the whole instruction is skipped!
let dst_reg = self.storage_manager.claim_general_reg(&mut self.buf, &dst);
let mov_start_index = self.buf.len();
ASM::mov_reg64_reg64(&mut self.buf, dst_reg, src_reg);
// jump to where the pointer is valid, because it is already valid if non-zero
let jmp_index = ASM::jne_reg64_imm64_imm32(&mut self.buf, reg, 0x0, 0);
let jmp_start_index = self.buf.len();
let jmp_end_index = ASM::jne_reg64_imm64_imm32(&mut self.buf, src_reg, 0x0, 0);
self.free_symbol(&dst);
// so, the pointer is NULL, allocate
let data_bytes = Symbol::DEV_TMP;
let data_bytes = self.debug_symbol("data_bytes");
self.load_layout_stack_size(layout, data_bytes);
// Load allocation alignment (u32)
let element_alignment = Symbol::DEV_TMP2;
self.load_layout_alignment(Layout::U32, element_alignment);
let element_alignment = self.debug_symbol("element_alignment");
self.load_layout_alignment(layout, element_alignment);
self.allocate_with_refcount(dst, data_bytes, element_alignment);
self.free_symbol(&data_bytes);
self.free_symbol(&element_alignment);
let mut tmp = bumpalo::vec![in self.env.arena];
// update the jump
let destination_index = self.buf.len();
let mut tmp = bumpalo::vec![in self.env.arena];
ASM::jne_reg64_imm64_imm32(&mut tmp, reg, 0x0, (destination_index - jmp_index) as i32);
ASM::jne_reg64_imm64_imm32(
&mut tmp,
src_reg,
0x0,
(destination_index - jmp_end_index) as i32,
);
self.buf[jmp_index..][..tmp.len()].copy_from_slice(tmp.as_slice());
self.buf[jmp_start_index..][..tmp.len()].copy_from_slice(tmp.as_slice());
// figure out what register was actually used
let dst_reg = self
.storage_manager
.load_to_general_reg(&mut self.buf, &dst);
tmp.clear();
ASM::mov_reg64_reg64(&mut tmp, dst_reg, src_reg);
self.buf[mov_start_index..][..tmp.len()].copy_from_slice(tmp.as_slice());
}
fn unbox_str_or_list(