mirror of
https://github.com/roc-lang/roc.git
synced 2025-07-24 06:55:15 +00:00
nullable unwrapped for the dev backend
This commit is contained in:
parent
0adf075123
commit
f6fafdb019
8 changed files with 198 additions and 10 deletions
|
@ -305,6 +305,10 @@ pub fn isUnique(
|
|||
|
||||
const isizes: [*]isize = @intToPtr([*]isize, masked_ptr);
|
||||
|
||||
if (DEBUG_INCDEC and builtin.target.cpu.arch != .wasm32) {
|
||||
std.debug.print("| is unique {*}\n", .{&bytes[0]});
|
||||
}
|
||||
|
||||
const refcount = (isizes - 1)[0];
|
||||
|
||||
return refcount == REFCOUNT_ONE_ISIZE;
|
||||
|
|
|
@ -458,6 +458,11 @@ impl CallConv<AArch64GeneralReg, AArch64FloatReg, AArch64Assembler> for AArch64C
|
|||
}
|
||||
|
||||
impl Assembler<AArch64GeneralReg, AArch64FloatReg> for AArch64Assembler {
|
||||
#[inline(always)]
|
||||
fn base_pointer() -> AArch64GeneralReg {
|
||||
AArch64GeneralReg::FP
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn abs_reg64_reg64(buf: &mut Vec<'_, u8>, dst: AArch64GeneralReg, src: AArch64GeneralReg) {
|
||||
cmp_reg64_imm12(buf, src, 0);
|
||||
|
|
|
@ -150,6 +150,8 @@ pub enum CompareOperation {
|
|||
/// Generally, I prefer explicit sources, as opposed to dst being one of the sources. Ex: `x = x + y` would be `add x, x, y` instead of `add x, y`.
|
||||
/// dst should always come before sources.
|
||||
pub trait Assembler<GeneralReg: RegTrait, FloatReg: RegTrait>: Sized + Copy {
|
||||
fn base_pointer() -> GeneralReg;
|
||||
|
||||
fn abs_reg64_reg64(buf: &mut Vec<'_, u8>, dst: GeneralReg, src: GeneralReg);
|
||||
fn abs_freg64_freg64(
|
||||
buf: &mut Vec<'_, u8>,
|
||||
|
@ -2629,6 +2631,49 @@ impl<
|
|||
);
|
||||
}
|
||||
|
||||
UnionLayout::NullableWrapped {
|
||||
nullable_id,
|
||||
other_tags,
|
||||
} => {
|
||||
debug_assert_ne!(tag_id, *nullable_id as TagIdIntType);
|
||||
|
||||
let other_fields = if tag_id < *nullable_id {
|
||||
other_tags[tag_id as usize]
|
||||
} else {
|
||||
other_tags[tag_id as usize - 1]
|
||||
};
|
||||
|
||||
let element_layout = other_fields[index as usize];
|
||||
|
||||
let ptr_reg = self
|
||||
.storage_manager
|
||||
.load_to_general_reg(&mut self.buf, structure);
|
||||
|
||||
let mask_symbol = self.debug_symbol("tag_id_mask");
|
||||
let mask_reg = self
|
||||
.storage_manager
|
||||
.claim_general_reg(&mut self.buf, &mask_symbol);
|
||||
ASM::mov_reg64_imm64(&mut self.buf, mask_reg, (!0b111) as _);
|
||||
|
||||
// mask out the tag id bits
|
||||
ASM::and_reg64_reg64_reg64(&mut self.buf, ptr_reg, ptr_reg, mask_reg);
|
||||
|
||||
let mut offset = 0;
|
||||
for field in &other_fields[..index as usize] {
|
||||
offset += self.layout_interner.stack_size(*field);
|
||||
}
|
||||
|
||||
Self::ptr_read(
|
||||
&mut self.buf,
|
||||
&mut self.storage_manager,
|
||||
self.layout_interner,
|
||||
ptr_reg,
|
||||
offset as i32,
|
||||
element_layout,
|
||||
*sym,
|
||||
);
|
||||
}
|
||||
|
||||
_ => {
|
||||
let union_in_layout = self
|
||||
.layout_interner
|
||||
|
@ -2780,6 +2825,72 @@ impl<
|
|||
|
||||
self.free_symbol(&tmp);
|
||||
}
|
||||
UnionLayout::NullableWrapped {
|
||||
nullable_id,
|
||||
other_tags,
|
||||
} => {
|
||||
let number_of_tags = other_tags.len() + 1;
|
||||
|
||||
let dst_reg = self.storage_manager.claim_general_reg(&mut self.buf, sym);
|
||||
|
||||
// build a table to index into with the value that we find
|
||||
let nullable_id = *nullable_id as usize;
|
||||
let it = std::iter::once(nullable_id)
|
||||
.chain(0..nullable_id)
|
||||
.chain(nullable_id + 1..number_of_tags);
|
||||
|
||||
let table = self.debug_symbol("tag_id_table");
|
||||
let table_offset = self
|
||||
.storage_manager
|
||||
.claim_stack_area(&table, (number_of_tags * 2) as _);
|
||||
|
||||
let mut offset = table_offset;
|
||||
for i in it {
|
||||
ASM::mov_reg64_imm64(&mut self.buf, dst_reg, i as i64);
|
||||
ASM::mov_base32_reg16(&mut self.buf, offset, dst_reg);
|
||||
|
||||
offset += 2;
|
||||
}
|
||||
|
||||
self.free_symbol(&table);
|
||||
|
||||
// mask the 3 lowest bits
|
||||
let tmp = Symbol::DEV_TMP5;
|
||||
let reg = self.storage_manager.claim_general_reg(&mut self.buf, &tmp);
|
||||
ASM::mov_reg64_imm64(&mut self.buf, reg, 0b111);
|
||||
|
||||
let src1_reg = reg;
|
||||
let src2_reg = self
|
||||
.storage_manager
|
||||
.load_to_general_reg(&mut self.buf, structure);
|
||||
|
||||
ASM::and_reg64_reg64_reg64(&mut self.buf, dst_reg, src1_reg, src2_reg);
|
||||
|
||||
// we're indexing into an array of u16, so double this index
|
||||
// also the stack grows down, so negate the index
|
||||
ASM::mov_reg64_imm64(&mut self.buf, reg, 2);
|
||||
ASM::umul_reg64_reg64_reg64(
|
||||
&mut self.buf,
|
||||
&mut self.storage_manager,
|
||||
dst_reg,
|
||||
dst_reg,
|
||||
reg,
|
||||
);
|
||||
|
||||
// index into the table
|
||||
let base_pointer = ASM::base_pointer();
|
||||
ASM::add_reg64_reg64_reg64(&mut self.buf, dst_reg, dst_reg, base_pointer);
|
||||
|
||||
// load the 16-bit value at the pointer
|
||||
ASM::mov_reg16_mem16_offset32(&mut self.buf, dst_reg, dst_reg, table_offset);
|
||||
|
||||
// keep only the lowest 16 bits
|
||||
ASM::mov_reg64_imm64(&mut self.buf, reg, 0xFFFF);
|
||||
ASM::and_reg64_reg64_reg64(&mut self.buf, dst_reg, dst_reg, reg);
|
||||
|
||||
self.free_symbol(&tmp);
|
||||
}
|
||||
|
||||
x => todo!("getting tag id of union with layout ({:?})", x),
|
||||
};
|
||||
}
|
||||
|
@ -2864,6 +2975,68 @@ impl<
|
|||
self.free_symbol(&temp_sym);
|
||||
}
|
||||
}
|
||||
UnionLayout::NullableWrapped {
|
||||
nullable_id,
|
||||
other_tags,
|
||||
} => {
|
||||
let nullable_id = *nullable_id;
|
||||
|
||||
if tag_id == nullable_id as TagIdIntType {
|
||||
// it's just a null pointer
|
||||
self.load_literal_i64(sym, 0);
|
||||
} else {
|
||||
let other_fields = if tag_id < nullable_id {
|
||||
other_tags[tag_id as usize]
|
||||
} else {
|
||||
other_tags[tag_id as usize - 1]
|
||||
};
|
||||
|
||||
// construct the payload as a struct on the stack
|
||||
let temp_sym = Symbol::DEV_TMP5;
|
||||
let layout = self
|
||||
.layout_interner
|
||||
.insert_no_semantic(LayoutRepr::Struct(other_fields));
|
||||
|
||||
self.load_literal_symbols(fields);
|
||||
self.storage_manager.create_struct(
|
||||
self.layout_interner,
|
||||
&mut self.buf,
|
||||
&temp_sym,
|
||||
&layout,
|
||||
fields,
|
||||
);
|
||||
|
||||
// now effectively box this struct
|
||||
let untagged_pointer_symbol = self.debug_symbol("untagged_pointer");
|
||||
self.expr_box(untagged_pointer_symbol, temp_sym, layout, reuse);
|
||||
|
||||
self.free_symbol(&temp_sym);
|
||||
|
||||
let tag_id_symbol = self.debug_symbol("tag_id");
|
||||
|
||||
// index zero is taken up by the nullable tag, so any tags before it in the
|
||||
// ordering need to be incremented by one
|
||||
let pointer_tag = if tag_id < nullable_id {
|
||||
tag_id + 1
|
||||
} else {
|
||||
tag_id
|
||||
};
|
||||
|
||||
// finally, we need to tag the pointer
|
||||
debug_assert!(tag_id < 8);
|
||||
self.load_literal_i64(&tag_id_symbol, pointer_tag as _);
|
||||
|
||||
self.build_int_bitwise_or(
|
||||
sym,
|
||||
&untagged_pointer_symbol,
|
||||
&tag_id_symbol,
|
||||
IntWidth::U64,
|
||||
);
|
||||
|
||||
self.free_symbol(&untagged_pointer_symbol);
|
||||
self.free_symbol(&tag_id_symbol);
|
||||
}
|
||||
}
|
||||
x => todo!("creating unions with layout: {:?}", x),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1139,6 +1139,11 @@ where
|
|||
}
|
||||
|
||||
impl Assembler<X86_64GeneralReg, X86_64FloatReg> for X86_64Assembler {
|
||||
#[inline(always)]
|
||||
fn base_pointer() -> X86_64GeneralReg {
|
||||
X86_64GeneralReg::RBP
|
||||
}
|
||||
|
||||
// These functions should map to the raw assembly functions below.
|
||||
// In some cases, that means you can just directly call one of the direct assembly functions.
|
||||
#[inline(always)]
|
||||
|
|
|
@ -4134,7 +4134,9 @@ where
|
|||
Unit => env
|
||||
.cache
|
||||
.put_in(Layout::new(LayoutRepr::UNIT, compute_semantic())),
|
||||
BoolUnion { .. } => Layout::BOOL,
|
||||
BoolUnion { .. } => env
|
||||
.cache
|
||||
.put_in(Layout::new(LayoutRepr::BOOL, compute_semantic())),
|
||||
ByteUnion(_) => env
|
||||
.cache
|
||||
.put_in(Layout::new(LayoutRepr::U8, compute_semantic())),
|
||||
|
|
|
@ -59,7 +59,7 @@ macro_rules! nosema {
|
|||
cache_interned_layouts! {
|
||||
0, VOID, pub, Layout::VOID_NAKED
|
||||
1, UNIT, pub, Layout::UNIT_NAKED
|
||||
2, BOOL, pub, Layout { repr: LayoutRepr::BOOL, semantic: SemanticRepr::BOOL }
|
||||
2, BOOL, pub, nosema!(LayoutRepr::BOOL)
|
||||
3, U8, pub, nosema!(LayoutRepr::U8)
|
||||
4, U16, pub, nosema!(LayoutRepr::U16)
|
||||
5, U32, pub, nosema!(LayoutRepr::U32)
|
||||
|
|
|
@ -27,21 +27,20 @@ enum Inner<'a> {
|
|||
impl<'a> SemanticRepr<'a> {
|
||||
pub(super) const NONE: Self = Self(Inner::None);
|
||||
pub(super) const EMPTY_RECORD: Self = Self::record(&[]);
|
||||
pub(super) const BOOL: Self = Self::tag_union(&["False", "True"]);
|
||||
|
||||
pub(super) const fn record(fields: &'a [&'a str]) -> Self {
|
||||
Self(Inner::Record(SemaRecord { fields }))
|
||||
}
|
||||
|
||||
pub(super) const fn tuple(size: usize) -> Self {
|
||||
pub(super) fn tuple(size: usize) -> Self {
|
||||
Self(Inner::Tuple(SemaTuple { size }))
|
||||
}
|
||||
|
||||
pub(super) const fn tag_union(tags: &'a [&'a str]) -> Self {
|
||||
pub(super) fn tag_union(tags: &'a [&'a str]) -> Self {
|
||||
Self(Inner::TagUnion(SemaTagUnion { tags }))
|
||||
}
|
||||
|
||||
pub(super) const fn lambdas(lambdas: &'a [Symbol]) -> Self {
|
||||
pub(super) fn lambdas(lambdas: &'a [Symbol]) -> Self {
|
||||
Self(Inner::Lambdas(SemaLambdas { lambdas }))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2063,7 +2063,7 @@ fn non_unary_union_with_lambda_set_with_imported_toplevels_issue_4733() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||
fn nullable_wrapped_with_non_nullable_singleton_tags() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -2094,7 +2094,7 @@ fn nullable_wrapped_with_non_nullable_singleton_tags() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||
fn nullable_wrapped_with_nullable_not_last_index() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -2102,9 +2102,9 @@ fn nullable_wrapped_with_nullable_not_last_index() {
|
|||
app "test" provides [main] to "./platform"
|
||||
|
||||
Parser : [
|
||||
OneOrMore Parser,
|
||||
Keyword Str,
|
||||
CharLiteral,
|
||||
Keyword Str,
|
||||
OneOrMore Parser,
|
||||
]
|
||||
|
||||
toIdParser : Parser -> Str
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue