diff --git a/crates/compiler/builtins/bitcode/src/main.zig b/crates/compiler/builtins/bitcode/src/main.zig index 6f0b59468d..672e1224ec 100644 --- a/crates/compiler/builtins/bitcode/src/main.zig +++ b/crates/compiler/builtins/bitcode/src/main.zig @@ -174,6 +174,7 @@ comptime { exportUtilsFn(utils.test_panic, "test_panic"); exportUtilsFn(utils.increfC, "incref"); exportUtilsFn(utils.decrefC, "decref"); + exportUtilsFn(utils.isUnique, "is_unique"); exportUtilsFn(utils.decrefCheckNullC, "decref_check_null"); exportUtilsFn(utils.allocateWithRefcountC, "allocate_with_refcount"); diff --git a/crates/compiler/builtins/bitcode/src/utils.zig b/crates/compiler/builtins/bitcode/src/utils.zig index 841b143863..79ae4200fa 100644 --- a/crates/compiler/builtins/bitcode/src/utils.zig +++ b/crates/compiler/builtins/bitcode/src/utils.zig @@ -231,6 +231,22 @@ inline fn decref_ptr_to_refcount( } } +pub export fn isUnique( + bytes_or_null: ?[*]u8, +) bool { + var bytes = bytes_or_null orelse return true; + + const ptr = @ptrToInt(bytes); + const tag_mask: usize = if (@sizeOf(usize) == 8) 0b111 else 0b11; + const masked_ptr = ptr & ~tag_mask; + + const isizes: [*]isize = @intToPtr([*]isize, masked_ptr); + + const refcount = (isizes - 1)[0]; + + return refcount == REFCOUNT_ONE_ISIZE; +} + // We follow roughly the [fbvector](https://github.com/facebook/folly/blob/main/folly/docs/FBVector.md) when it comes to growing a RocList. // Here is [their growth strategy](https://github.com/facebook/folly/blob/3e0525988fd444201b19b76b390a5927c15cb697/folly/FBVector.h#L1128) for push_back: // diff --git a/crates/compiler/builtins/src/bitcode.rs b/crates/compiler/builtins/src/bitcode.rs index d96496eae9..5eefcde053 100644 --- a/crates/compiler/builtins/src/bitcode.rs +++ b/crates/compiler/builtins/src/bitcode.rs @@ -377,6 +377,7 @@ pub const UTILS_TEST_PANIC: &str = "roc_builtins.utils.test_panic"; pub const UTILS_ALLOCATE_WITH_REFCOUNT: &str = "roc_builtins.utils.allocate_with_refcount"; pub const UTILS_INCREF: &str = "roc_builtins.utils.incref"; pub const UTILS_DECREF: &str = "roc_builtins.utils.decref"; +pub const UTILS_IS_UNIQUE: &str = "roc_builtins.utils.is_unique"; pub const UTILS_DECREF_CHECK_NULL: &str = "roc_builtins.utils.decref_check_null"; pub const UTILS_EXPECT_FAILED_START_SHARED_BUFFER: &str = diff --git a/crates/compiler/can/src/builtins.rs b/crates/compiler/can/src/builtins.rs index aafbff85a7..2dcf24a271 100644 --- a/crates/compiler/can/src/builtins.rs +++ b/crates/compiler/can/src/builtins.rs @@ -87,6 +87,7 @@ macro_rules! map_symbol_to_lowlevel_and_arity { LowLevel::PtrCast => unimplemented!(), LowLevel::RefCountInc => unimplemented!(), LowLevel::RefCountDec => unimplemented!(), + LowLevel::RefCountIsUnique => unimplemented!(), // these are not implemented, not sure why LowLevel::StrFromInt => unimplemented!(), diff --git a/crates/compiler/gen_llvm/src/llvm/lowlevel.rs b/crates/compiler/gen_llvm/src/llvm/lowlevel.rs index e7c115e003..d57253de2a 100644 --- a/crates/compiler/gen_llvm/src/llvm/lowlevel.rs +++ b/crates/compiler/gen_llvm/src/llvm/lowlevel.rs @@ -1251,6 +1251,11 @@ pub(crate) fn run_low_level<'a, 'ctx, 'env>( unreachable!("Not used in LLVM backend: {:?}", op); } + RefCountIsUnique => { + arguments!(input); + call_bitcode_fn(env, &[input], &bitcode::UTILS_IS_UNIQUE) + } + Unreachable => match RocReturn::from_layout(env, layout_interner, layout) { RocReturn::Return => { let basic_type = basic_type_from_layout(env, layout_interner, layout); diff --git a/crates/compiler/gen_wasm/src/low_level.rs b/crates/compiler/gen_wasm/src/low_level.rs index 6cfd49bea3..6e248275ee 100644 --- a/crates/compiler/gen_wasm/src/low_level.rs +++ b/crates/compiler/gen_wasm/src/low_level.rs @@ -1949,6 +1949,7 @@ impl<'a> LowLevelCall<'a> { } RefCountInc => self.load_args_and_call_zig(backend, bitcode::UTILS_INCREF), RefCountDec => self.load_args_and_call_zig(backend, bitcode::UTILS_DECREF), + RefCountIsUnique => self.load_args_and_call_zig(backend, bitcode::UTILS_IS_UNIQUE), PtrCast => { let code_builder = &mut backend.code_builder; diff --git a/crates/compiler/module/src/low_level.rs b/crates/compiler/module/src/low_level.rs index 7c72a0ec3d..4f9f8dab9a 100644 --- a/crates/compiler/module/src/low_level.rs +++ b/crates/compiler/module/src/low_level.rs @@ -117,6 +117,7 @@ pub enum LowLevel { PtrCast, RefCountInc, RefCountDec, + RefCountIsUnique, BoxExpr, UnboxExpr, Unreachable, @@ -221,6 +222,7 @@ macro_rules! map_symbol_to_lowlevel { LowLevel::PtrCast => unimplemented!(), LowLevel::RefCountInc => unimplemented!(), LowLevel::RefCountDec => unimplemented!(), + LowLevel::RefCountIsUnique => unimplemented!(), // these are not implemented, not sure why LowLevel::StrFromInt => unimplemented!(), diff --git a/crates/compiler/mono/src/borrow.rs b/crates/compiler/mono/src/borrow.rs index 85861f859f..229d7e360c 100644 --- a/crates/compiler/mono/src/borrow.rs +++ b/crates/compiler/mono/src/borrow.rs @@ -1031,7 +1031,7 @@ pub fn lowlevel_borrow_signature(arena: &Bump, op: LowLevel) -> &[Ownership] { unreachable!("These lowlevel operations are turned into mono Expr's") } - PtrCast | RefCountInc | RefCountDec => { + PtrCast | RefCountInc | RefCountDec | RefCountIsUnique => { unreachable!("Only inserted *after* borrow checking: {:?}", op); } }