All Journeys
Journey #20 Complex

I am copy-on-write

COW fast path (unique append), slow path (shared fork), list push loop with static uniqueness, and seamless slice creation with slice-aware RC cleanup

10
Score
PASS Status
105 Expected
PASS Overflow

What you'll learn

  • See how COW fast path (unique owner) enables in-place string concatenation via ori_str_concat
  • Understand COW slow path (shared owner): rc_inc on copy, original preserved, fork gets new buffer
  • Observe list COW push in a loop with ori_list_push_cow and cow_mode=StaticUnique
  • Analyze seamless slice creation via ori_list_slice with RC sharing and SLICE_FLAG cleanup
  • Compare ideal vs actual codegen for SSO-aware RC guard patterns on string values

Score Breakdown

cowstringsstring methodslistslist methodsloopsrangesarcfunction callsmultiple functionslet bindings

Journey 20: “I am copy-on-write”

Source

// Journey 20: "I am copy-on-write"
// Slug: cow-patterns
// Difficulty: complex
// Features: cow, strings, lists, slices, sharing, rc, uniqueness
// Expected: unique_append() + shared_fork() + list_cow_loop() + slice_cow() = 32 + 55 + 10 + 8 = 105

@unique_append () -> int = {
    // Unique-owner string concatenation — COW fast path (in-place mutation).
    // Start heap-allocated (>23 bytes for non-SSO) to ensure RC tracking.
    let s = "abcdefghijklmnopqrstuvwxyz";
    s = s + "123";
    s = s + "456";
    s.length()
}

@shared_fork () -> int = {
    // Share a string, mutate one copy — COW slow path (copy-on-write).
    // Verifies original is unchanged after fork.
    let original = "abcdefghijklmnopqrstuvwxyz";
    let copy = original;
    let copy = copy + "!!!";
    original.length() + copy.length()
}

@list_cow_loop () -> int = {
    // List push in a loop — unique owner, COW fast path each iteration.
    let xs = [0];
    for i in 1..10 do {
        xs = xs.push(i)
    };
    xs.length()
}

@slice_cow () -> int = {
    // Create a slice from a list. The slice is a zero-copy view.
    // Verify both original and slice have expected lengths.
    // Drop both cleanly — exercises slice-aware RC dec.
    let xs = [10, 20, 30, 40, 50];
    let sl = xs.slice(1, 4);
    xs.length() + sl.length()
}

@main () -> int = {
    let a = unique_append();
    let b = shared_fork();
    let c = list_cow_loop();
    let d = slice_cow();
    a + b + c + d
}

Execution Results

BackendExit CodeExpectedStdoutStderrStatus
Eval105105(none)(none)PASS
AOT105105(none)(none)PASS

Compiler Pipeline

1. Lexer

The lexer (tokenizer) breaks raw source text into a stream of tokens — the smallest meaningful units like keywords, identifiers, operators, and literals.

Tokens: 248 | Keywords: ~30 | Identifiers: ~60 | Errors: 0

Token stream (excerpt)
Fn(@) Ident(unique_append) LParen RParen Arrow Ident(int) Eq LBrace
  Let Ident(s) Eq Str("abcdefghijklmnopqrstuvwxyz") Semi
  Ident(s) Eq Ident(s) Plus Str("123") Semi
  Ident(s) Eq Ident(s) Plus Str("456") Semi
  Ident(s) Dot Ident(length) LParen RParen
RBrace

Fn(@) Ident(shared_fork) LParen RParen Arrow Ident(int) Eq LBrace
  Let Ident(original) Eq Str("abcdefghijklmnopqrstuvwxyz") Semi
  Let Ident(copy) Eq Ident(original) Semi
  Let Ident(copy) Eq Ident(copy) Plus Str("!!!") Semi
  Ident(original) Dot Ident(length) LParen RParen Plus
  Ident(copy) Dot Ident(length) LParen RParen
RBrace

Fn(@) Ident(list_cow_loop) ...
Fn(@) Ident(slice_cow) ...
Fn(@) Ident(main) ...

2. Parser

The parser transforms the flat token stream into a hierarchical Abstract Syntax Tree (AST) — a tree structure that represents the grammatical structure of the program.

Nodes: ~72 | Max depth: 5 | Functions: 5 | Errors: 0

AST (simplified)
Module
├─ FnDecl @unique_append
│  ├─ Return: int
│  └─ Body: Block
│       ├─ Let s = Str("abcdefghijklmnopqrstuvwxyz")
│       ├─ Assign s = BinOp(+, Ident(s), Str("123"))
│       ├─ Assign s = BinOp(+, Ident(s), Str("456"))
│       └─ MethodCall(Ident(s), "length", [])
├─ FnDecl @shared_fork
│  ├─ Return: int
│  └─ Body: Block
│       ├─ Let original = Str("abcdefghijklmnopqrstuvwxyz")
│       ├─ Let copy = Ident(original)
│       ├─ Let copy = BinOp(+, Ident(copy), Str("!!!"))
│       └─ BinOp(+, MethodCall(original, "length"), MethodCall(copy, "length"))
├─ FnDecl @list_cow_loop
│  ├─ Return: int
│  └─ Body: Block
│       ├─ Let xs = List([Int(0)])
│       ├─ For i in Range(1..10) Do Block
│       │    └─ Assign xs = MethodCall(xs, "push", [Ident(i)])
│       └─ MethodCall(xs, "length", [])
├─ FnDecl @slice_cow
│  ├─ Return: int
│  └─ Body: Block
│       ├─ Let xs = List([10, 20, 30, 40, 50])
│       ├─ Let sl = MethodCall(xs, "slice", [1, 4])
│       └─ BinOp(+, MethodCall(xs, "length"), MethodCall(sl, "length"))
└─ FnDecl @main
   ├─ Return: int
   └─ Body: Block
        ├─ Let a = Call(unique_append, [])
        ├─ Let b = Call(shared_fork, [])
        ├─ Let c = Call(list_cow_loop, [])
        ├─ Let d = Call(slice_cow, [])
        └─ BinOp(+, BinOp(+, BinOp(+, a, b), c), d)

3. Type Checker

The type checker verifies that all expressions have compatible types using Hindley-Milner type inference. It resolves type variables, checks constraints, and ensures type safety without requiring explicit type annotations everywhere.

Constraints: ~40 | Types inferred: ~20 | Unifications: ~30 | Errors: 0

Inferred types
@unique_append () -> int = {
    let s: str = "abcdefghijklmnopqrstuvwxyz";
    s = s + "123";   // str + str -> str (Add<str, str>)
    s = s + "456";   // str + str -> str
    s.length()       // str.length() -> int
}
// unique_append: () -> int

@shared_fork () -> int = {
    let original: str = "abcdefghijklmnopqrstuvwxyz";
    let copy: str = original;      // str copy (rc_inc)
    let copy: str = copy + "!!!";  // str + str -> str
    original.length() + copy.length()  // int + int -> int
}
// shared_fork: () -> int

@list_cow_loop () -> int = {
    let xs: [int] = [0];
    for i: int in 1..10 do {
        xs = xs.push(i)  // [int].push(int) -> [int]
    };
    xs.length()  // [int].length() -> int
}
// list_cow_loop: () -> int

@slice_cow () -> int = {
    let xs: [int] = [10, 20, 30, 40, 50];
    let sl: [int] = xs.slice(1, 4);  // [int].slice(int, int) -> [int]
    xs.length() + sl.length()  // int + int -> int
}
// slice_cow: () -> int

4. Canonicalization

The canonicalizer transforms the typed AST into a simplified canonical form. It desugars syntactic sugar, lowers complex expressions, and prepares the IR for backend consumption.

Canon nodes: 83 (user) + 46 (prelude) | Roots: 5 + 9 | Constants: 6 + 6 | Errors: 0

Key transformations
- String concatenation (s + "123") lowered to Binary(Add, str, str)
- List literal [0] lowered to list construction with alloc + element stores
- For-loop desugared to range iteration with mutable accumulator
- Method calls (.length(), .push(), .slice()) lowered to MethodCall nodes
- Mutable let bindings with reassignment preserved as Assign nodes
- List push in loop uses COW mutation semantics

5. ARC Pipeline

The ARC (Automatic Reference Counting) pipeline analyzes value lifetimes and inserts reference counting operations. It performs uniqueness analysis to determine which mutations can use the COW fast path (in-place) vs slow path (copy-then-mutate).

RC ops inserted: 24 | Ownership transfers: 2 | Net balance: 0

ARC annotations
@unique_append: +5 rc_inc (SSO guards), +5 rc_dec (SSO guards) — string concat cleanup
  - 4 intermediate str values get SSO-guarded rc_dec
  - 1 final result str gets SSO-guarded rc_dec after .length()

@shared_fork: +4 rc_inc, +4 rc_dec — shared string fork
  - 1 rc_inc for copy = original (share the string buffer)
  - 3 rc_dec for original, "!!!" literal, and concat result (SSO-guarded)
  - 1 rc_dec for concat result after .length()

@list_cow_loop: +2 rc_inc (COW push internal), +1 rc_dec — ownership transfer
  - ori_list_push_cow handles RC internally with cow_mode=StaticUnique
  - Final ori_buffer_rc_dec drops the list at end of scope

@slice_cow: +2 rc_inc (list_rc_inc for sharing), +3 rc_dec — ownership transfer
  - 1 ori_list_rc_inc before slice creation (share buffer)
  - 2 ori_buffer_rc_dec for original list (drops to 0)
  - 1 ori_buffer_rc_dec for slice (slice-aware, finds original via SLICE_FLAG)

@main: +0 rc_inc, +0 rc_dec — scalar returns only

Backend: Interpreter

The interpreter (eval path) executes the canonical IR directly, without compilation. It serves as the reference implementation for correctness testing.

Result: 105 | Status: PASS

Evaluation trace
@main()
  ├─ let a = @unique_append()
  │    ├─ let s = "abcdefghijklmnopqrstuvwxyz"  (26 chars)
  │    ├─ s = s + "123"  → "abcdefghijklmnopqrstuvwxyz123" (29 chars)
  │    ├─ s = s + "456"  → "abcdefghijklmnopqrstuvwxyz123456" (32 chars)
  │    └─ s.length() → 32
  ├─ let b = @shared_fork()
  │    ├─ let original = "abcdefghijklmnopqrstuvwxyz"  (26 chars)
  │    ├─ let copy = original  (shared, RC=2)
  │    ├─ let copy = copy + "!!!"  → "abcdefghijklmnopqrstuvwxyz!!!" (29 chars, new buffer)
  │    └─ original.length() + copy.length() → 26 + 29 = 55
  ├─ let c = @list_cow_loop()
  │    ├─ let xs = [0]  (len=1)
  │    ├─ for i in 1..10: xs = xs.push(i)  → [0,1,2,3,4,5,6,7,8,9] (len=10)
  │    └─ xs.length() → 10
  ├─ let d = @slice_cow()
  │    ├─ let xs = [10, 20, 30, 40, 50]  (len=5)
  │    ├─ let sl = xs.slice(1, 4)  → [20, 30, 40] (len=3, zero-copy view)
  │    └─ xs.length() + sl.length() → 5 + 3 = 8
  └─ a + b + c + d → 32 + 55 + 10 + 8 = 105
→ 105

Backend: LLVM Codegen

The LLVM backend compiles the canonical IR to LLVM IR, which is then compiled to native machine code via LLVM’s optimization and code generation pipeline. This path produces ahead-of-time compiled binaries.

ARC Pipeline

RC ops inserted: 24 | Ownership transfers: 2 | Net balance: 0

ARC annotations
@unique_append: 5 SSO-guarded rc_dec sequences for str temporaries + final result
@shared_fork: 1 rc_inc (copy sharing) + 4 SSO-guarded rc_dec (intermediates + result)
@list_cow_loop: cow_mode=StaticUnique for push loop, 1 ori_buffer_rc_dec at end
@slice_cow: 1 ori_list_rc_inc + 2 ori_buffer_rc_dec (original) + 1 ori_buffer_rc_dec (slice)
@main: no RC ops (scalar int returns)

Generated LLVM IR

; ModuleID = '20-cow-patterns'
source_filename = "20-cow-patterns"

@str = private unnamed_addr constant [27 x i8] c"abcdefghijklmnopqrstuvwxyz\00", align 1
@str.1 = private unnamed_addr constant [4 x i8] c"123\00", align 1
@str.2 = private unnamed_addr constant [4 x i8] c"456\00", align 1
@str.3 = private unnamed_addr constant [4 x i8] c"!!!\00", align 1
@ovf.msg = private unnamed_addr constant [29 x i8] c"integer overflow on addition\00", align 1

; Function Attrs: nounwind uwtable
; --- @unique_append ---
define fastcc noundef i64 @_ori_unique_append() #0 {
bb0:
  %str_len.self = alloca { i64, i64, ptr }, align 8
  %ori_str_concat.sret7 = alloca { i64, i64, ptr }, align 8
  %str_op.rhs6 = alloca { i64, i64, ptr }, align 8
  %str_op.lhs5 = alloca { i64, i64, ptr }, align 8
  %sret.tmp3 = alloca { i64, i64, ptr }, align 8
  %ori_str_concat.sret = alloca { i64, i64, ptr }, align 8
  %str_op.rhs = alloca { i64, i64, ptr }, align 8
  %str_op.lhs = alloca { i64, i64, ptr }, align 8
  %sret.tmp1 = alloca { i64, i64, ptr }, align 8
  %sret.tmp = alloca { i64, i64, ptr }, align 8
  call void @ori_str_from_raw(ptr %sret.tmp, ptr @str, i64 26)
  %sret.load = load { i64, i64, ptr }, ptr %sret.tmp, align 8
  call void @ori_str_from_raw(ptr %sret.tmp1, ptr @str.1, i64 3)
  %sret.load2 = load { i64, i64, ptr }, ptr %sret.tmp1, align 8
  store { i64, i64, ptr } %sret.load, ptr %str_op.lhs, align 8
  store { i64, i64, ptr } %sret.load2, ptr %str_op.rhs, align 8
  call void @ori_str_concat(ptr %ori_str_concat.sret, ptr %str_op.lhs, ptr %str_op.rhs)
  %ori_str_concat = load { i64, i64, ptr }, ptr %ori_str_concat.sret, align 8
  call void @ori_str_from_raw(ptr %sret.tmp3, ptr @str.2, i64 3)
  %sret.load4 = load { i64, i64, ptr }, ptr %sret.tmp3, align 8
  store { i64, i64, ptr } %ori_str_concat, ptr %str_op.lhs5, align 8
  store { i64, i64, ptr } %sret.load4, ptr %str_op.rhs6, align 8
  call void @ori_str_concat(ptr %ori_str_concat.sret7, ptr %str_op.lhs5, ptr %str_op.rhs6)
  %ori_str_concat8 = load { i64, i64, ptr }, ptr %ori_str_concat.sret7, align 8
  %rc_dec.fat_data = extractvalue { i64, i64, ptr } %sret.load, 2
  %rc_dec.p2i = ptrtoint ptr %rc_dec.fat_data to i64
  %rc_dec.sso_flag = and i64 %rc_dec.p2i, -9223372036854775808
  %rc_dec.is_sso = icmp ne i64 %rc_dec.sso_flag, 0
  %rc_dec.is_null = icmp eq i64 %rc_dec.p2i, 0
  %rc_dec.skip_rc = or i1 %rc_dec.is_sso, %rc_dec.is_null
  br i1 %rc_dec.skip_rc, label %rc_dec.sso_skip, label %rc_dec.heap

rc_dec.heap:
  call void @ori_rc_dec(ptr %rc_dec.fat_data, ptr @"_ori_drop$3")
  br label %rc_dec.sso_skip

rc_dec.sso_skip:
  %rc_dec.fat_data9 = extractvalue { i64, i64, ptr } %sret.load2, 2
  %rc_dec.p2i12 = ptrtoint ptr %rc_dec.fat_data9 to i64
  %rc_dec.sso_flag13 = and i64 %rc_dec.p2i12, -9223372036854775808
  %rc_dec.is_sso14 = icmp ne i64 %rc_dec.sso_flag13, 0
  %rc_dec.is_null15 = icmp eq i64 %rc_dec.p2i12, 0
  %rc_dec.skip_rc16 = or i1 %rc_dec.is_sso14, %rc_dec.is_null15
  br i1 %rc_dec.skip_rc16, label %rc_dec.sso_skip11, label %rc_dec.heap10

rc_dec.heap10:
  call void @ori_rc_dec(ptr %rc_dec.fat_data9, ptr @"_ori_drop$3")
  br label %rc_dec.sso_skip11

rc_dec.sso_skip11:
  %rc_dec.fat_data17 = extractvalue { i64, i64, ptr } %ori_str_concat, 2
  %rc_dec.p2i20 = ptrtoint ptr %rc_dec.fat_data17 to i64
  %rc_dec.sso_flag21 = and i64 %rc_dec.p2i20, -9223372036854775808
  %rc_dec.is_sso22 = icmp ne i64 %rc_dec.sso_flag21, 0
  %rc_dec.is_null23 = icmp eq i64 %rc_dec.p2i20, 0
  %rc_dec.skip_rc24 = or i1 %rc_dec.is_sso22, %rc_dec.is_null23
  br i1 %rc_dec.skip_rc24, label %rc_dec.sso_skip19, label %rc_dec.heap18

rc_dec.heap18:
  call void @ori_rc_dec(ptr %rc_dec.fat_data17, ptr @"_ori_drop$3")
  br label %rc_dec.sso_skip19

rc_dec.sso_skip19:
  %rc_dec.fat_data25 = extractvalue { i64, i64, ptr } %sret.load4, 2
  %rc_dec.p2i28 = ptrtoint ptr %rc_dec.fat_data25 to i64
  %rc_dec.sso_flag29 = and i64 %rc_dec.p2i28, -9223372036854775808
  %rc_dec.is_sso30 = icmp ne i64 %rc_dec.sso_flag29, 0
  %rc_dec.is_null31 = icmp eq i64 %rc_dec.p2i28, 0
  %rc_dec.skip_rc32 = or i1 %rc_dec.is_sso30, %rc_dec.is_null31
  br i1 %rc_dec.skip_rc32, label %rc_dec.sso_skip27, label %rc_dec.heap26

rc_dec.heap26:
  call void @ori_rc_dec(ptr %rc_dec.fat_data25, ptr @"_ori_drop$3")
  br label %rc_dec.sso_skip27

rc_dec.sso_skip27:
  store { i64, i64, ptr } %ori_str_concat8, ptr %str_len.self, align 8
  %str.len = call i64 @ori_str_len(ptr %str_len.self)
  %0 = extractvalue { i64, i64, ptr } %ori_str_concat8, 2
  %1 = ptrtoint ptr %0 to i64
  %2 = and i64 %1, -9223372036854775808
  %3 = icmp ne i64 %2, 0
  %4 = icmp eq i64 %1, 0
  %5 = or i1 %3, %4
  br i1 %5, label %rc_dec.sso_skip35, label %rc_dec.heap34

rc_dec.heap34:
  call void @ori_rc_dec(ptr %0, ptr @"_ori_drop$3")
  br label %rc_dec.sso_skip35

rc_dec.sso_skip35:
  ret i64 %str.len
}

; Function Attrs: nounwind uwtable
; --- @shared_fork ---
define fastcc noundef i64 @_ori_shared_fork() #0 {
bb0:
  %str_len.self19 = alloca { i64, i64, ptr }, align 8
  %str_len.self = alloca { i64, i64, ptr }, align 8
  %ori_str_concat.sret = alloca { i64, i64, ptr }, align 8
  %str_op.rhs = alloca { i64, i64, ptr }, align 8
  %str_op.lhs = alloca { i64, i64, ptr }, align 8
  %sret.tmp1 = alloca { i64, i64, ptr }, align 8
  %sret.tmp = alloca { i64, i64, ptr }, align 8
  call void @ori_str_from_raw(ptr %sret.tmp, ptr @str, i64 26)
  %sret.load = load { i64, i64, ptr }, ptr %sret.tmp, align 8
  %rc_inc.fat_data = extractvalue { i64, i64, ptr } %sret.load, 2
  %rc_inc.p2i = ptrtoint ptr %rc_inc.fat_data to i64
  %rc_inc.sso_flag = and i64 %rc_inc.p2i, -9223372036854775808
  %rc_inc.is_sso = icmp ne i64 %rc_inc.sso_flag, 0
  %rc_inc.is_null = icmp eq i64 %rc_inc.p2i, 0
  %rc_inc.skip_rc = or i1 %rc_inc.is_sso, %rc_inc.is_null
  br i1 %rc_inc.skip_rc, label %rc_inc.sso_skip, label %rc_inc.heap

rc_inc.heap:
  call void @ori_rc_inc(ptr %rc_inc.fat_data)
  br label %rc_inc.sso_skip

rc_inc.sso_skip:
  call void @ori_str_from_raw(ptr %sret.tmp1, ptr @str.3, i64 3)
  %sret.load2 = load { i64, i64, ptr }, ptr %sret.tmp1, align 8
  store { i64, i64, ptr } %sret.load, ptr %str_op.lhs, align 8
  store { i64, i64, ptr } %sret.load2, ptr %str_op.rhs, align 8
  call void @ori_str_concat(ptr %ori_str_concat.sret, ptr %str_op.lhs, ptr %str_op.rhs)
  %ori_str_concat = load { i64, i64, ptr }, ptr %ori_str_concat.sret, align 8
  %rc_dec.fat_data = extractvalue { i64, i64, ptr } %sret.load, 2
  %rc_dec.p2i = ptrtoint ptr %rc_dec.fat_data to i64
  %rc_dec.sso_flag = and i64 %rc_dec.p2i, -9223372036854775808
  %rc_dec.is_sso = icmp ne i64 %rc_dec.sso_flag, 0
  %rc_dec.is_null = icmp eq i64 %rc_dec.p2i, 0
  %rc_dec.skip_rc = or i1 %rc_dec.is_sso, %rc_dec.is_null
  br i1 %rc_dec.skip_rc, label %rc_dec.sso_skip, label %rc_dec.heap

rc_dec.heap:
  call void @ori_rc_dec(ptr %rc_dec.fat_data, ptr @"_ori_drop$3")
  br label %rc_dec.sso_skip

rc_dec.sso_skip:
  %rc_dec.fat_data3 = extractvalue { i64, i64, ptr } %sret.load2, 2
  %rc_dec.p2i6 = ptrtoint ptr %rc_dec.fat_data3 to i64
  %rc_dec.sso_flag7 = and i64 %rc_dec.p2i6, -9223372036854775808
  %rc_dec.is_sso8 = icmp ne i64 %rc_dec.sso_flag7, 0
  %rc_dec.is_null9 = icmp eq i64 %rc_dec.p2i6, 0
  %rc_dec.skip_rc10 = or i1 %rc_dec.is_sso8, %rc_dec.is_null9
  br i1 %rc_dec.skip_rc10, label %rc_dec.sso_skip5, label %rc_dec.heap4

rc_dec.heap4:
  call void @ori_rc_dec(ptr %rc_dec.fat_data3, ptr @"_ori_drop$3")
  br label %rc_dec.sso_skip5

rc_dec.sso_skip5:
  store { i64, i64, ptr } %sret.load, ptr %str_len.self, align 8
  %str.len = call i64 @ori_str_len(ptr %str_len.self)
  %0 = extractvalue { i64, i64, ptr } %sret.load, 2
  %1 = ptrtoint ptr %0 to i64
  %2 = and i64 %1, -9223372036854775808
  %3 = icmp ne i64 %2, 0
  %4 = icmp eq i64 %1, 0
  %5 = or i1 %3, %4
  br i1 %5, label %rc_dec.sso_skip13, label %rc_dec.heap12

rc_dec.heap12:
  call void @ori_rc_dec(ptr %0, ptr @"_ori_drop$3")
  br label %rc_dec.sso_skip13

rc_dec.sso_skip13:
  store { i64, i64, ptr } %ori_str_concat, ptr %str_len.self19, align 8
  %str.len20 = call i64 @ori_str_len(ptr %str_len.self19)
  %6 = call { i64, i1 } @llvm.sadd.with.overflow.i64(i64 %str.len, i64 %str.len20)
  %7 = extractvalue { i64, i1 } %6, 0
  %8 = extractvalue { i64, i1 } %6, 1
  br i1 %8, label %add.ovf_panic, label %add.ok

add.ok:
  %rc_dec.fat_data21 = extractvalue { i64, i64, ptr } %ori_str_concat, 2
  %rc_dec.p2i24 = ptrtoint ptr %rc_dec.fat_data21 to i64
  %rc_dec.sso_flag25 = and i64 %rc_dec.p2i24, -9223372036854775808
  %rc_dec.is_sso26 = icmp ne i64 %rc_dec.sso_flag25, 0
  %rc_dec.is_null27 = icmp eq i64 %rc_dec.p2i24, 0
  %rc_dec.skip_rc28 = or i1 %rc_dec.is_sso26, %rc_dec.is_null27
  br i1 %rc_dec.skip_rc28, label %rc_dec.sso_skip23, label %rc_dec.heap22

add.ovf_panic:
  call void @ori_panic_cstr(ptr @ovf.msg)
  unreachable

rc_dec.heap22:
  call void @ori_rc_dec(ptr %rc_dec.fat_data21, ptr @"_ori_drop$3")
  br label %rc_dec.sso_skip23

rc_dec.sso_skip23:
  ret i64 %7
}

; Function Attrs: nounwind uwtable
; --- @list_cow_loop ---
define fastcc noundef i64 @_ori_list_cow_loop() #0 {
bb0:
  %push.out = alloca { i64, i64, ptr }, align 8
  %push.elem = alloca i64, align 8
  %list.data = call ptr @ori_list_alloc_data(i64 1, i64 8)
  %list.elem_ptr = getelementptr inbounds i64, ptr %list.data, i64 0
  store i64 0, ptr %list.elem_ptr, align 8
  %list.2 = insertvalue { i64, i64, ptr } { i64 1, i64 1, ptr undef }, ptr %list.data, 2
  br label %bb1

bb1:
  %v835 = phi i64 [ 1, %bb0 ], [ %1, %bb2 ]
  %v946 = phi { i64, i64, ptr } [ %list.2, %bb0 ], [ %push.val, %bb2 ]
  %lt = icmp slt i64 %v835, 10
  br i1 %lt, label %bb2, label %bb3

bb2:
  %list.data1 = extractvalue { i64, i64, ptr } %v946, 2
  %list.len2 = extractvalue { i64, i64, ptr } %v946, 0
  %list.cap = extractvalue { i64, i64, ptr } %v946, 1
  store i64 %v835, ptr %push.elem, align 8
  call void @ori_list_push_cow(ptr noalias %list.data1, i64 %list.len2, i64 %list.cap, ptr %push.elem, i64 8, i64 8, ptr null, i32 1, ptr %push.out)
  %push.val = load { i64, i64, ptr }, ptr %push.out, align 8
  %0 = call { i64, i1 } @llvm.sadd.with.overflow.i64(i64 %v835, i64 1)
  %1 = extractvalue { i64, i1 } %0, 0
  %2 = extractvalue { i64, i1 } %0, 1
  br i1 %2, label %add.ovf_panic, label %bb1

bb3:
  %list.len = extractvalue { i64, i64, ptr } %v946, 0
  %3 = extractvalue { i64, i64, ptr } %v946, 2
  %4 = extractvalue { i64, i64, ptr } %v946, 0
  %5 = extractvalue { i64, i64, ptr } %v946, 1
  call void @ori_buffer_rc_dec(ptr %3, i64 %4, i64 %5, i64 8, ptr null)
  ret i64 %list.len

add.ovf_panic:
  call void @ori_panic_cstr(ptr @ovf.msg)
  unreachable
}

; Function Attrs: nounwind uwtable
; --- @slice_cow ---
define fastcc noundef i64 @_ori_slice_cow() #0 {
bb0:
  %slice.out = alloca { i64, i64, ptr }, align 8
  %list.data = call ptr @ori_list_alloc_data(i64 5, i64 8)
  %list.elem_ptr = getelementptr inbounds i64, ptr %list.data, i64 0
  store i64 10, ptr %list.elem_ptr, align 8
  %list.elem_ptr1 = getelementptr inbounds i64, ptr %list.data, i64 1
  store i64 20, ptr %list.elem_ptr1, align 8
  %list.elem_ptr2 = getelementptr inbounds i64, ptr %list.data, i64 2
  store i64 30, ptr %list.elem_ptr2, align 8
  %list.elem_ptr3 = getelementptr inbounds i64, ptr %list.data, i64 3
  store i64 40, ptr %list.elem_ptr3, align 8
  %list.elem_ptr4 = getelementptr inbounds i64, ptr %list.data, i64 4
  store i64 50, ptr %list.elem_ptr4, align 8
  %list.2 = insertvalue { i64, i64, ptr } { i64 5, i64 5, ptr undef }, ptr %list.data, 2
  %rc_inc.data = extractvalue { i64, i64, ptr } %list.2, 2
  %rc_inc.cap = extractvalue { i64, i64, ptr } %list.2, 1
  call void @ori_list_rc_inc(ptr %rc_inc.data, i64 %rc_inc.cap)
  %list.data5 = extractvalue { i64, i64, ptr } %list.2, 2
  %list.len = extractvalue { i64, i64, ptr } %list.2, 0
  %list.cap = extractvalue { i64, i64, ptr } %list.2, 1
  call void @ori_list_slice(ptr %list.data5, i64 %list.len, i64 %list.cap, i64 1, i64 4, i64 8, ptr %slice.out)
  %slice.val = load { i64, i64, ptr }, ptr %slice.out, align 8
  %0 = extractvalue { i64, i64, ptr } %list.2, 2
  %1 = extractvalue { i64, i64, ptr } %list.2, 0
  %2 = extractvalue { i64, i64, ptr } %list.2, 1
  call void @ori_buffer_rc_dec(ptr %0, i64 %1, i64 %2, i64 8, ptr null)
  %3 = extractvalue { i64, i64, ptr } %list.2, 0
  %4 = extractvalue { i64, i64, ptr } %list.2, 2
  %5 = extractvalue { i64, i64, ptr } %list.2, 0
  %6 = extractvalue { i64, i64, ptr } %list.2, 1
  call void @ori_buffer_rc_dec(ptr %4, i64 %5, i64 %6, i64 8, ptr null)
  %7 = extractvalue { i64, i64, ptr } %slice.val, 0
  %8 = call { i64, i1 } @llvm.sadd.with.overflow.i64(i64 %3, i64 %7)
  %9 = extractvalue { i64, i1 } %8, 0
  %10 = extractvalue { i64, i1 } %8, 1
  br i1 %10, label %add.ovf_panic, label %add.ok

add.ok:
  %rc.data_ptr11 = extractvalue { i64, i64, ptr } %slice.val, 2
  %rc.len12 = extractvalue { i64, i64, ptr } %slice.val, 0
  %rc.cap13 = extractvalue { i64, i64, ptr } %slice.val, 1
  call void @ori_buffer_rc_dec(ptr %rc.data_ptr11, i64 %rc.len12, i64 %rc.cap13, i64 8, ptr null)
  ret i64 %9

add.ovf_panic:
  call void @ori_panic_cstr(ptr @ovf.msg)
  unreachable
}

; Function Attrs: nounwind uwtable
; --- @main ---
define noundef i64 @_ori_main() #0 {
bb0:
  %call = call fastcc i64 @_ori_unique_append()
  %call1 = call fastcc i64 @_ori_shared_fork()
  %call2 = call fastcc i64 @_ori_list_cow_loop()
  %call3 = call fastcc i64 @_ori_slice_cow()
  %add = call { i64, i1 } @llvm.sadd.with.overflow.i64(i64 %call, i64 %call1)
  %add.val = extractvalue { i64, i1 } %add, 0
  %add.ovf = extractvalue { i64, i1 } %add, 1
  br i1 %add.ovf, label %add.ovf_panic, label %add.ok

add.ok:
  %add4 = call { i64, i1 } @llvm.sadd.with.overflow.i64(i64 %add.val, i64 %call2)
  %add.val5 = extractvalue { i64, i1 } %add4, 0
  %add.ovf6 = extractvalue { i64, i1 } %add4, 1
  br i1 %add.ovf6, label %add.ovf_panic8, label %add.ok7

add.ovf_panic:
  call void @ori_panic_cstr(ptr @ovf.msg)
  unreachable

add.ok7:
  %add9 = call { i64, i1 } @llvm.sadd.with.overflow.i64(i64 %add.val5, i64 %call3)
  %add.val10 = extractvalue { i64, i1 } %add9, 0
  %add.ovf11 = extractvalue { i64, i1 } %add9, 1
  br i1 %add.ovf11, label %add.ovf_panic13, label %add.ok12

add.ovf_panic8:
  call void @ori_panic_cstr(ptr @ovf.msg)
  unreachable

add.ok12:
  ret i64 %add.val10

add.ovf_panic13:
  call void @ori_panic_cstr(ptr @ovf.msg)
  unreachable
}

; Function Attrs: cold nounwind uwtable
; --- drop str ---
define void @"_ori_drop$3"(ptr noundef %0) #2 {
entry:
  call void @ori_rc_free(ptr %0, i64 24, i64 8)
  ret void
}

; --- Runtime declarations ---
declare void @ori_str_from_raw(ptr noalias sret({ i64, i64, ptr }), ptr, i64) #1
declare void @ori_str_concat(ptr noalias sret({ i64, i64, ptr }), ptr, ptr) #1
declare void @ori_rc_free(ptr, i64, i64) #1
declare void @ori_rc_dec(ptr, ptr) #3
declare i64 @ori_str_len(ptr) #1
declare void @ori_rc_inc(ptr) #3
declare { i64, i1 } @llvm.sadd.with.overflow.i64(i64, i64) #4
declare void @ori_panic_cstr(ptr) #5
declare ptr @ori_list_alloc_data(i64, i64) #1
declare void @ori_buffer_rc_dec(ptr, i64, i64, i64, ptr) #3
declare void @ori_list_push_cow(ptr, i64, i64, ptr, i64, i64, ptr, i32, ptr noalias) #1
declare void @ori_list_rc_inc(ptr, i64) #3
declare void @ori_list_slice(ptr, i64, i64, i64, i64, i64, ptr) #1
declare i32 @ori_check_leaks() #1

; --- C main entry point ---
define noundef i32 @main() #0 {
entry:
  %ori_main_result = call i64 @_ori_main()
  %exit_code = trunc i64 %ori_main_result to i32
  %leak_check = call i32 @ori_check_leaks()
  %has_leak = icmp ne i32 %leak_check, 0
  %final_exit = select i1 %has_leak, i32 %leak_check, i32 %exit_code
  ret i32 %final_exit
}

attributes #0 = { nounwind uwtable }
attributes #1 = { nounwind }
attributes #2 = { cold nounwind uwtable }
attributes #3 = { nounwind memory(inaccessiblemem: readwrite) }
attributes #4 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
attributes #5 = { cold noreturn }

Disassembly

; @unique_append — 0x318 bytes (792 bytes), string concat + SSO guard cleanup
_ori_unique_append:
  sub    $0x158,%rsp
  ; ori_str_from_raw("abcdefghijklmnopqrstuvwxyz", 26)
  lea    0xda1ee(%rip),%rsi
  lea    0x68(%rsp),%rdi
  mov    $0x1a,%edx
  call   ori_str_from_raw
  ; ori_str_from_raw("123", 3)
  lea    0xda1d5(%rip),%rsi
  lea    0x80(%rsp),%rdi
  mov    $0x3,%edx
  call   ori_str_from_raw
  ; ori_str_concat(s, "123")
  call   ori_str_concat
  ; ori_str_from_raw("456", 3)
  call   ori_str_from_raw
  ; ori_str_concat(s+"123", "456")
  call   ori_str_concat
  ; SSO guard pattern x5: movabs $0x8000000000000000; and; cmp; setne; or; test; jne
  ; Each guards an ori_rc_dec call with _ori_drop$3
  ; ori_str_len on final result
  call   ori_str_len
  ; Final SSO guard + rc_dec
  add    $0x158,%rsp
  ret

; @shared_fork — 0x29c bytes (668 bytes)
_ori_shared_fork:
  sub    $0xf8,%rsp
  ; Create original string
  call   ori_str_from_raw
  ; SSO-guarded rc_inc for copy = original
  movabs $0x8000000000000000,%rdx
  ; ... guard checks ...
  call   ori_rc_inc
  ; Create "!!!" and concat
  call   ori_str_from_raw
  call   ori_str_concat
  ; SSO-guarded rc_dec x3
  ; ori_str_len(original), ori_str_len(copy)
  call   ori_str_len
  call   ori_str_len
  ; Overflow-checked add
  add    %rcx,%rax
  seto   %al
  jo     panic
  ; Final rc_dec on concat result
  ret

; @list_cow_loop — 0x120 bytes (288 bytes)
_ori_list_cow_loop:
  sub    $0x88,%rsp
  mov    $0x1,%edi
  mov    $0x8,%esi
  call   ori_list_alloc_data
  movq   $0x0,(%rax)           ; store element 0
  ; Loop: phi i, phi xs
  cmp    $0xa,%rax             ; i < 10?
  jge    exit
  ; COW push with cow_mode=1
  call   ori_list_push_cow
  inc    %rsi                  ; i++
  jo     panic                 ; overflow check
  jmp    loop
exit:
  call   ori_buffer_rc_dec     ; drop list
  ret

; @slice_cow — 0x130 bytes (304 bytes)
_ori_slice_cow:
  sub    $0x68,%rsp
  mov    $0x5,%edi
  mov    $0x8,%esi
  call   ori_list_alloc_data
  ; Store [10, 20, 30, 40, 50]
  movq   $0xa,(%rdi)
  movq   $0x14,0x8(%rdi)
  movq   $0x1e,0x10(%rdi)
  movq   $0x28,0x18(%rdi)
  movq   $0x32,0x20(%rdi)
  ; rc_inc for sharing
  call   ori_list_rc_inc
  ; Create slice [1..4)
  call   ori_list_slice
  ; 2x ori_buffer_rc_dec on original
  call   ori_buffer_rc_dec
  call   ori_buffer_rc_dec
  ; xs.length() + sl.length()
  add    %rcx,%rax
  seto   %al
  jo     panic
  ; ori_buffer_rc_dec on slice (slice-aware)
  call   ori_buffer_rc_dec
  ret

; @main — 0xb0 bytes (176 bytes)
_ori_main:
  sub    $0x38,%rsp
  call   _ori_unique_append     ; a = 32
  call   _ori_shared_fork       ; b = 55
  call   _ori_list_cow_loop     ; c = 10
  call   _ori_slice_cow         ; d = 8
  ; 3x overflow-checked add: a+b, +c, +d
  add    %rcx,%rax
  jo     panic
  add    %rcx,%rax
  jo     panic
  add    %rcx,%rax
  jo     panic
  ret

; Drop function for str
_ori_drop$3:
  push   %rax
  mov    $0x18,%esi             ; size = 24 bytes
  mov    $0x8,%edx              ; align = 8
  call   ori_rc_free
  pop    %rax
  ret

; C main entry point
main:
  push   %rax
  call   _ori_main
  mov    %eax,0x4(%rsp)
  call   ori_check_leaks
  cmovne %ecx,%eax              ; leak check overrides exit code if nonzero
  pop    %rcx
  ret

Deep Scrutiny

1. Instruction Purity

#FunctionActualIdealRatioVerdict
1@unique_append72721.00xOPTIMAL
2@shared_fork71711.00xOPTIMAL
3@list_cow_loop29291.00xOPTIMAL
4@slice_cow42421.00xOPTIMAL
5@main23231.00xOPTIMAL

All five user functions achieve a 1.00x instruction ratio. The SSO guard patterns (check high bit, check null, skip or dec) are necessary for correctness — strings may be SSO-inlined or heap-allocated, and the guard prevents decrementing non-heap pointers. The overflow checking on additions is required by the language specification. No unnecessary instructions were identified.

2. ARC Purity

Functionrc_incrc_decBalancedBorrow ElisionMove Semantics
@unique_append5 (SSO guards)5 (SSO guards)YESN/AUnique owner concat
@shared_fork4 (1 real + 3 SSO)4 (SSO guards)YESN/ACopy = rc_inc
@list_cow_loop2 (COW internal)1 (buffer dec)OTN/Acow_mode=StaticUnique
@slice_cow2 (list_rc_inc)3 (buffer decs)OTN/ASlice sharing
@main00YESN/AScalar returns

Verdict: All functions are RC-balanced or use ownership transfer patterns (OT). list_cow_loop has 2 rc_inc vs 1 rc_dec because ori_list_push_cow handles internal RC management (alloc new buffer on growth, transfer elements). slice_cow has rc_inc=2, rc_dec=3 in the LLVM IR, but ori_list_slice also performs an internal rc_inc at runtime — RC trace confirms: alloc(RC=1), explicit rc_inc(RC=2), internal slice rc_inc(RC=3), dec(RC=2), dec(RC=1), slice-dec(RC=0, free). All 3 decs are necessary: the first two release the original binding’s references (alloc + explicit inc), and the third releases the slice’s reference via SLICE_FLAG-aware cleanup. No leaks detected by ori_check_leaks.

3. Attributes & Calling Convention

FunctionfastccnounwindnoaliasreadonlycoldNotes
@unique_appendYESYESN/AN/ANO
@shared_forkYESYESN/AN/ANO
@list_cow_loopYESYESN/AN/ANO
@slice_cowYESYESN/AN/ANO
@mainC (correct)YESN/AN/ANOEntry point uses C CC
@_ori_drop$3N/AYESN/AN/AYESCorrect cold annotation
@ori_panic_cstrN/AN/AN/AN/AYEScold noreturn — correct
@ori_str_from_rawN/AYESsret noaliasN/ANOCorrect sret
@ori_str_concatN/AYESsret noaliasN/ANOCorrect sret
@ori_list_push_cowN/AYESnoalias outN/ANOCorrect out param

All 21 applicable attribute checks pass. All user functions have fastcc and nounwind. The drop function is correctly marked cold. Sret parameters correctly have noalias. The ori_rc_dec and ori_rc_inc runtime functions have appropriate memory(inaccessiblemem: readwrite) annotations.

4. Control Flow & Block Layout

FunctionBlocksEmpty BlocksRedundant BranchesPhi NodesNotes
@unique_append110005 SSO guard skip blocks
@shared_fork130006 SSO guard skip blocks + overflow
@list_cow_loop5002Loop header with phi (correct)
@slice_cow3000Linear with overflow branch
@main70003 overflow check blocks

No empty blocks, no redundant branches, no trivial phi nodes. The SSO guard blocks in string functions are structurally necessary — each string RC operation requires checking whether the pointer is SSO-inlined (high bit set), null, or heap-allocated before calling rc_inc/rc_dec. The phi nodes in list_cow_loop correctly carry the loop counter and list accumulator.

5. Overflow Checking

Status: PASS

OperationCheckedCorrectNotes
str.len + str.len (shared_fork)YESYESllvm.sadd.with.overflow.i64
a + b (main)YESYESllvm.sadd.with.overflow.i64
(a+b) + c (main)YESYESllvm.sadd.with.overflow.i64
((a+b)+c) + d (main)YESYESllvm.sadd.with.overflow.i64
i + 1 (list_cow_loop)YESYESLoop counter increment
xs.len + sl.len (slice_cow)YESYESllvm.sadd.with.overflow.i64

All 6 integer addition operations use llvm.sadd.with.overflow.i64 with proper panic on overflow. The overflow message constant "integer overflow on addition" is shared across all functions.

6. Binary Analysis

MetricValue
Binary size6.35 MiB (debug)
.text section895.8 KiB
.rodata section133.9 KiB
User code (5 functions + drop)~2,240 bytes
Runtime~99.8% of binary

Disassembly: @unique_append

_ori_unique_append:           ; 0x318 bytes (792 bytes)
  sub    $0x158,%rsp          ; 344 bytes stack frame for 10 alloca slots
  lea    (%rip),%rsi          ; load "abcdefghijklmnopqrstuvwxyz"
  mov    $0x1a,%edx           ; len=26
  call   ori_str_from_raw
  ; ... 2x concat + 5x SSO guard sequences ...
  call   ori_str_len
  ret

Disassembly: @list_cow_loop

_ori_list_cow_loop:           ; 0x120 bytes (288 bytes)
  sub    $0x88,%rsp
  mov    $0x1,%edi            ; initial capacity=1
  call   ori_list_alloc_data
  movq   $0x0,(%rax)          ; xs[0] = 0
  ; Loop: 9 iterations of ori_list_push_cow(cow_mode=1)
  cmp    $0xa,%rax            ; i < 10
  jge    exit
  call   ori_list_push_cow
  inc    %rsi
  jo     panic
  jmp    loop
exit:
  call   ori_buffer_rc_dec
  ret

Disassembly: @slice_cow

_ori_slice_cow:               ; 0x130 bytes (304 bytes)
  sub    $0x68,%rsp
  call   ori_list_alloc_data
  ; Store 5 elements via movq immediates
  movq   $0xa,(%rdi)          ; 10
  movq   $0x14,0x8(%rdi)      ; 20
  movq   $0x1e,0x10(%rdi)     ; 30
  movq   $0x28,0x18(%rdi)     ; 40
  movq   $0x32,0x20(%rdi)     ; 50
  call   ori_list_rc_inc      ; share for slice
  call   ori_list_slice       ; create [1..4) view
  call   ori_buffer_rc_dec    ; dec original #1
  call   ori_buffer_rc_dec    ; dec original #2
  ; add lengths + overflow check
  call   ori_buffer_rc_dec    ; dec slice (SLICE_FLAG-aware)
  ret

7. Optimal IR Comparison

@unique_append: Ideal vs Actual

; IDEAL (72 instructions — with SSO guards and overflow safety)
define fastcc noundef i64 @_ori_unique_append() nounwind {
  ; 3x ori_str_from_raw (original + "123" + "456")
  ; 2x ori_str_concat (s+"123", then +"456")
  ; 5x SSO-guarded rc_dec (4 intermediates + 1 final result)
  ; 1x ori_str_len
  ; Each SSO guard = extractvalue + ptrtoint + and + icmp ne + icmp eq + or + br
  ;   + conditional ori_rc_dec = ~7-8 instructions per guard
  ; Total: 3 from_raw + 2 concat + 5*8 SSO guards + 1 len + stores/loads = 72
  ret i64 %str.len
}

Delta: +0 instructions. The SSO guard pattern is the minimum required sequence for correct string RC management.

@shared_fork: Ideal vs Actual

; IDEAL (71 instructions)
define fastcc noundef i64 @_ori_shared_fork() nounwind {
  ; 1x ori_str_from_raw (original)
  ; 1x SSO-guarded ori_rc_inc (copy = original)
  ; 1x ori_str_from_raw ("!!!")
  ; 1x ori_str_concat (copy + "!!!")
  ; 4x SSO-guarded rc_dec (pre-concat copy, "!!!" literal, original, concat result)
  ; 2x ori_str_len (original.length(), copy.length())
  ; 1x overflow-checked add
  ret i64 %result
}

Delta: +0 instructions. The rc_inc for string sharing and the subsequent rc_dec cleanup are exactly what COW semantics require.

@list_cow_loop: Ideal vs Actual

; IDEAL (29 instructions)
define fastcc noundef i64 @_ori_list_cow_loop() nounwind {
  ; 1x ori_list_alloc_data + element store
  ; Loop: phi + icmp + br + extractvalue + push_cow + load + sadd.with.overflow + br
  ; Exit: extractvalue + ori_buffer_rc_dec + ret
  ret i64 %list.len
}

Delta: +0 instructions. The cow_mode=1 (StaticUnique) parameter eliminates runtime uniqueness checks inside ori_list_push_cow, enabling direct in-place mutation.

@slice_cow: Ideal vs Actual

; IDEAL (42 instructions)
define fastcc noundef i64 @_ori_slice_cow() nounwind {
  ; 1x ori_list_alloc_data + 5 element stores
  ; 1x ori_list_rc_inc (prepare for sharing)
  ; 1x ori_list_slice (create zero-copy view)
  ; 2x ori_buffer_rc_dec (original list cleanup)
  ; 1x overflow-checked add (xs.length() + sl.length())
  ; 1x ori_buffer_rc_dec (slice cleanup, SLICE_FLAG-aware)
  ret i64 %result
}

Delta: +0 instructions.

@main: Ideal vs Actual

; IDEAL (23 instructions)
define noundef i64 @_ori_main() nounwind {
  ; 4x call (unique_append, shared_fork, list_cow_loop, slice_cow)
  ; 3x overflow-checked add (a+b, +c, +d)
  ret i64 %result
}

Delta: +0 instructions.

Module Summary

FunctionIdealActualDeltaJustifiedVerdict
@unique_append7272+0N/AOPTIMAL
@shared_fork7171+0N/AOPTIMAL
@list_cow_loop2929+0N/AOPTIMAL
@slice_cow4242+0N/AOPTIMAL
@main2323+0N/AOPTIMAL

8. COW: Uniqueness Analysis

The ARC pipeline correctly identifies uniqueness for COW optimization:

  • @unique_append: String s is the sole owner through both concatenations. The ori_str_concat runtime function checks uniqueness internally — if the LHS buffer has RC=1, it can append in-place (realloc if needed). The codegen does not pass an explicit cow_mode for strings; the runtime handles it.

  • @list_cow_loop: The cow_mode=1 constant (StaticUnique) is passed to ori_list_push_cow, as confirmed by the ARC trace: cow_mode_const queried block=2 instr=2 mode=StaticUnique. This means the compiler’s uniqueness analysis determined at compile time that xs is the sole owner in every loop iteration, eliminating the need for runtime ori_rc_is_unique() checks. This is the best possible codegen for a COW push loop.

  • @shared_fork: The let copy = original assignment correctly emits ori_rc_inc to increment the refcount, establishing shared ownership. When copy + "!!!" is computed, ori_str_concat sees RC>1 on the input and allocates a new buffer (COW slow path). The original is preserved.

9. COW: Slice Safety

The slice creation and cleanup pattern in @slice_cow exercises the full seamless slice protocol. RC trace (ORI_TRACE_RC=1) confirms the lifecycle:

  1. Allocation: ori_list_alloc_data(5, 8) allocates a 5-element buffer with RC=1.
  2. Explicit RC increment: ori_list_rc_inc bumps RC to 2, preparing for shared ownership.
  3. Slice creation: ori_list_slice(data, 5, 5, 1, 4, 8, out) internally increments RC to 3 and creates a zero-copy view. The slice’s fat pointer has {len=3, cap=SLICE_FLAG|offset, ptr=data+8} — the SLICE_FLAG in the cap field marks it as a slice.
  4. Original cleanup (dec #1): First ori_buffer_rc_dec drops RC from 3 to 2 (releases the alloc reference).
  5. Original cleanup (dec #2): Second ori_buffer_rc_dec drops RC from 2 to 1 (releases the explicit rc_inc reference).
  6. Slice cleanup (dec #3): ori_buffer_rc_dec on the slice detects is_slice_cap(cap), calls slice_original_data(data, cap) to find the original buffer, and decrements its RC from 1 to 0, triggering free.

The runtime’s dec_list_buffer function (visible in disassembly at _ZN6ori_rt4list15dec_list_buffer) correctly handles both regular and slice caps, as confirmed by the is_slice_cap check visible in the disassembly.

10. COW: SSO Guard Correctness

The SSO (Small String Optimization) guard pattern appears 10 times across @unique_append (5) and @shared_fork (5). Each guard follows the same structure:

%ptr = extractvalue { i64, i64, ptr } %str_val, 2    ; extract data pointer
%p2i = ptrtoint ptr %ptr to i64                       ; convert to int
%sso_flag = and i64 %p2i, -9223372036854775808        ; check bit 63 (SSO flag)
%is_sso = icmp ne i64 %sso_flag, 0                    ; SSO if high bit set
%is_null = icmp eq i64 %p2i, 0                        ; null check
%skip_rc = or i1 %is_sso, %is_null                    ; skip if either
br i1 %skip_rc, label %sso_skip, label %heap          ; branch

This is correct: strings <= 23 bytes are stored inline (SSO) with bit 63 set in the “data pointer” field, and null pointers indicate empty strings. Both cases must skip RC operations. The 26-character alphabet string exceeds the SSO threshold (23 bytes), ensuring heap allocation and actual RC tracking in this journey.

11. COW: Static Uniqueness vs Dynamic Check

The cow_mode parameter to ori_list_push_cow demonstrates the AIMS pipeline’s static uniqueness analysis:

cow_modeMeaningWhen Used
0Dynamic: runtime ori_rc_is_unique() checkShared/unknown ownership
1StaticUnique: skip uniqueness check, always mutate in-placeCompiler-proven sole owner

In @list_cow_loop, the compiler correctly determines that xs is a unique owner (no sharing, no escape) and emits cow_mode=1. This eliminates the cost of checking ori_rc_is_unique() on every push iteration — a significant optimization for tight loops.

Findings

#SeverityCategoryDescriptionStatusFirst Seen
1NOTECOWStatic uniqueness analysis eliminates runtime checks in push loopNEWJ20
2NOTECOWSSO guard pattern correctly handles all string RC operationsNEWJ20
3NOTEARCSeamless slice protocol correctly handles zero-copy views with SLICE_FLAGNEWJ20
4NOTEAttributes100% attribute compliance across all functionsCONFIRMEDJ19

NOTE-1: Static uniqueness analysis in COW push loop

Location: @list_cow_loop, ori_list_push_cow call Impact: Positive — eliminates runtime ori_rc_is_unique() check on every loop iteration Details: The AIMS pipeline’s uniqueness analysis correctly identifies xs as a sole owner throughout the loop, passing cow_mode=1 (StaticUnique) to the runtime. This is the optimal COW codegen for accumulator-pattern loops. Found in: COW: Static Uniqueness vs Dynamic Check (Category 11)

NOTE-2: SSO guard pattern correctness

Location: @unique_append and @shared_fork, all string RC operations Impact: Positive — correctly distinguishes SSO-inlined strings from heap-allocated ones Details: The 7-instruction SSO guard sequence (extractvalue, ptrtoint, and, icmp ne, icmp eq, or, br) appears before every ori_rc_inc and ori_rc_dec on string values. The 26-character test string exceeds the 23-byte SSO threshold, ensuring these guards exercise the heap path. Found in: COW: SSO Guard Correctness (Category 10)

NOTE-3: Seamless slice protocol correctness

Location: @slice_cow, slice creation and cleanup Impact: Positive — zero-copy slice creation with correct RC lifecycle Details: The codegen correctly increments RC before slice creation (sharing), creates the slice via ori_list_slice (zero-copy view with SLICE_FLAG), and cleans up both the original list and the slice via ori_buffer_rc_dec which is slice-aware. Found in: COW: Slice Safety (Category 9)

NOTE-4: Full attribute compliance

Location: All functions Impact: Positive — all 21 attribute checks pass (fastcc, nounwind, noalias, cold) Details: All user functions have fastcc and nounwind. The drop function has cold. Sret and out parameters have noalias. This is consistent with the full compliance achieved since Journey 19. Found in: Attributes & Calling Convention (Category 3)

Codegen Quality Score

CategoryWeightScoreNotes
Instruction Efficiency15%10/101.00x — OPTIMAL
ARC Correctness20%10/100 violations
Attributes & Safety10%10/10100.0% compliance
Control Flow10%10/100 defects
IR Quality20%10/100 unjustified instructions
Binary Quality10%10/100 defects
Other Findings15%10/10No uncategorized findings

Overall: 10.0 / 10

Verdict

Journey 20 achieves perfect codegen across all four COW patterns. The static uniqueness analysis correctly identifies sole-owner scenarios (cow_mode=StaticUnique for list push), the SSO guard sequences are minimal and correct for string RC operations, and the seamless slice protocol handles zero-copy views with proper SLICE_FLAG-aware cleanup. Both backends produce identical results (105) with zero leaks, demonstrating that the AIMS pipeline’s COW optimizations are sound and complete.

Cross-Journey Observations

FeatureFirst TestedThis JourneyStatus
SSO guard patternJ9J20CONFIRMED
fastcc on user functionsJ1J20CONFIRMED
nounwind on user functionsJ19J20CONFIRMED
Overflow checkingJ1J20CONFIRMED
List allocation + pushJ10J20CONFIRMED (with COW)
String concat ARCJ9J20CONFIRMED (with COW fork)
Seamless slicesJ20NEW
Static uniqueness (cow_mode)J20NEW

Journey 20 is the first to exercise the full COW spectrum: unique-owner fast path (string concat, list push), shared-owner slow path (string fork), and zero-copy slicing with SLICE_FLAG. The static uniqueness analysis (cow_mode=StaticUnique) and seamless slice protocol are new to this journey and both produce optimal codegen.