Luce / engineering
Learn Luce LuciaOS

Closure environments

make_adder returns code that still remembers start after the function has returned. That memory lives in a small ARC-managed environment carried beside the code pointer.

Follow one captured value

MIR separates the closure body from the environment it reads. LLVM gives the environment a concrete layout and calling convention. ARM64 allocates it, stores the captured integer, calls through the function value, and releases the environment when it is no longer reachable.

Compiler traceFollow one program through four representations
compiler build information

Luce source. Names and indentation describe the program for a reader.

open source file

func make_adder(start: i64) -> func(i64) -> i64:
    let add: func(i64) -> i64 = func(value):
        return start + value
    return add

func main(args: list[str]):
    let add = make_adder(len(args))
    print(str(add(2)))

Luce MIR. Types, registers, blocks, calls, and lifetime operations form the instruction plan sent to the LLVM backend.

open MIR file
MIR instruction guide hover, focus, or tap dotted terms

r7 is one typed intermediate value, %2 is a local storage slot, and b1 is a basic block. Read each block from top to bottom, then follow its final control-flow instruction.

Hover or focus a dotted term in the file for its explanation. On a touch screen, tap a term to keep the note open and tap elsewhere to close it. The list includes the operations that appear in this file.

class NAME
Declares a reference type with shared identity. Its fields live in an ARC-managed runtime object.
func …
Starts one MIR function and lists the source-level parameters with their resolved types.
local %N
Reserves a typed local slot. The slot gives later blocks a stable place to read or replace.
b0, b1, …
Names a basic block. Control enters at the label and runs until a branch, jump, trap, or return chooses what happens next.
r0, r1, …
Names one typed intermediate result. Each register is assigned once, which makes data flow explicit.
local_get
Reads a local slot into a fresh MIR register so this use has a precise value and type.
local_set
Writes a register into a local slot. Later blocks read that slot after control-flow paths join.
const
Creates a typed literal such as 2 or 10 inside the instruction stream.
add.i64
Adds two signed 64-bit integers. The type suffix selects the overflow and representation rules.
intrinsic NAME
Invokes a language operation with runtime rules recorded by the compiler. The name identifies the operation.
intrinsic len
Reads the logical length defined by the value's type, such as argument count or Unicode-scalar count.
intrinsic str_value
Converts a typed value into owned text through Luce's string conversion rules.
intrinsic print
Sends text through the installed host output capability.
intrinsic retain
Adds one strong owner before another place begins holding the same reference.
intrinsic release
Removes one strong owner and runs destruction when the count reaches zero.
intrinsic own_storage
Turns temporary storage into an owned value that can safely outlive the current expression.
intrinsic drop_storage
Releases any reference held by a temporary value and leaves that temporary in its empty state.
call NAME
Calls a resolved function directly. MIR already knows the target and argument order.
call_indirect
Calls through a function value containing code plus an optional captured environment.
const_function
Creates a function value for a named function whose code address is known.
struct_make
Builds a value aggregate from fields in declared layout order.
struct_get
Extracts one field from a value aggregate.
ret
Returns the current function's result to its caller and closes the current control-flow path.

class make_adder.(closure@2.33).(environment):
    start: i64
func make_adder(start: i64) -> func(i64) -> i64
    local %1 (temporary): func(i64) -> i64
    local %2 add: func(i64) -> i64
  b0:
    r0 = local_get %0
    r1 = struct_make make_adder.(closure@2.33).(environment), r0
    r2 = const_function make_adder.(closure@2.33) bound r1
    local_set %2, r2
    r4 = local_get %2
    intrinsic retain, r4
    r6 = intrinsic own_storage, r4
    r7 = local_get %2
    intrinsic release, r7
    r9 = local_get %2
    r10 = intrinsic drop_storage, r9
    local_set %2, r10
    ret r6
func main(args: list[str]) -> None
    local %1 (temporary): func(i64) -> i64
    local %2 add: func(i64) -> i64
    local %3 (temporary): str
  b0:
    r0 = local_get %0
    r1 = intrinsic len, r0
    r2 = call make_adder, r1
    local_set %2, r2
    r4 = local_get %2
    r5 = const 2
    r6 = call_indirect r4 : func(i64) -> i64, r5
    r7 = intrinsic str_value, r6
    local_set %3, r7
    intrinsic print, r7
    r10 = local_get %3
    r11 = intrinsic drop_storage, r10
    local_set %3, r11
    r13 = local_get %2
    intrinsic release, r13
    r15 = local_get %2
    r16 = intrinsic drop_storage, r15
    local_set %2, r16
    ret
func make_adder.(closure@2.33)($closure: make_adder.(closure@2.33).(environment), value: i64) -> i64
    local %2 start: i64
  b0:
    r0 = local_get %0
    r1 = struct_get r0, make_adder.(closure@2.33).(environment).start
    local_set %2, r1
    r3 = local_get %2
    r4 = local_get %1
    r5 = add.i64 r3, r4
    ret r5

LLVM IR. The backend expands MIR into typed memory operations, calls, checks, and control-flow blocks for LLVM.

open LLVM IR file
LLVM IR instruction guide hover, focus, or tap dotted terms

%7 is an SSA value, i64 is a 64-bit integer type, ptr is a pointer, and @name is a module symbol. Numbered labels divide the function into basic blocks.

Hover or focus a dotted term in the file for its explanation. On a touch screen, tap a term to keep the note open and tap elsewhere to close it. The list includes the operations that appear in this file.

@name = …
Defines module data such as text constants, source positions, function records, and the artifact identity tag.
define … @name
Begins a generated function. The parameter attributes tell LLVM which pointers are valid, writable, or read-only.
declare … @name
Declares a runtime or LLVM helper whose body is provided elsewhere.
numeric label
Starts an LLVM basic block. Every branch names one of these labels as its destination.
%0, %1, …
Names an SSA value. Each name is assigned once, allowing LLVM to trace definitions and uses directly.
alloca
Reserves a stack slot for a local value, return area, or temporary aggregate.
getelementptr
Calculates the address of a field or indexed element while preserving LLVM's type and bounds information.
load
Copies a typed value from memory into an SSA value.
store
Copies an SSA value into a stack slot, object field, return area, or runtime structure.
icmp
Compares integers or pointers and produces the one-bit condition consumed by a branch or select.
br
Transfers control to another block. With an i1 operand it chooses between two destinations.
select
Chooses one of two SSA values from a condition, which can become a branch-free machine instruction.
call
Invokes a generated function, a runtime helper, a host callback, or an LLVM intrinsic.
extractvalue
Reads one field from an SSA aggregate, such as the result and overflow bit returned together.
insertvalue
Builds an SSA aggregate one field at a time.
ptrtoint
Encodes a pointer as an integer field inside Luce's uniform runtime value representation.
inttoptr
Recovers a pointer from the integer field of Luce's uniform runtime value representation.
zext
Widens an unsigned value by filling the new high bits with zero.
trunc
Keeps the low bits while converting to a narrower integer representation.
lshr
Shifts bits right and fills the high side with zero; this is useful for unpacking handle fields.
and
Combines or masks bits, often to inspect a flag in a packed handle or status value.
or
Sets or combines bits in a packed value.
sub
Subtracts integer values; the generated entry code also uses it to update the call-depth budget.
mul
Multiplies integers after the language-specific checks have been represented.
ret
Returns a status or value and ends the current basic block.
@llvm.sadd.with.overflow.i64
Returns a signed sum together with the overflow bit required by checked addition.
@llvm.memcpy.inline
Copies a small fixed-size value representation; LLVM can expand it directly for the target.
@luce_rt_open
Creates the per-run runtime state and installs the table used to turn function numbers into source-aware traces.
@luce_rt_close
Closes the per-run runtime state after the final status and reports have been collected.
@luce_rt_args_list
Builds the owned list[str] passed to main from the host's argument callbacks.
@luce_rt_status
Combines the generated function result with runtime trap, error, exhaustion, and exit state.
@luce_rt_report_error
Sends an uncaught recoverable error through the host's error-report callback.
@luce_rt_report
Sends the completed trap report through the host callback selected by the entry wrapper.
@luce_rt_leaked
Reads the live-object count used to detect references that remain after program cleanup.
@luce_rt_exhaust
Records allocation exhaustion in the current run so the entry wrapper returns the corresponding status.
@luce_rt_raise
Records a source-aware trap in the runtime so every execution path reports the same code and location.
@luce_rt_unwound
Adds one generated function frame while a trap or uncaught error travels toward the entry point.
@luce_rt_retain
Adds a strong owner to a runtime object handle.
@luce_rt_release
Removes a strong owner and triggers destruction at zero.
@luce_rt_own_storage
Turns temporary storage into an owned runtime value for a destination or result.
@luce_rt_drop_storage
Releases reference-bearing fields in a temporary runtime value.
@luce_rt_str
Converts a uniform runtime value into owned UTF-8 text.
@luce_rt_class_make
Allocates and initializes storage for a class identity.
@luce_rt_class_get
Loads a field from class storage after validating the object handle.
@luce_rt_function_make
Builds a callable value from a code address and its retained closure environment.
@luce_rt_files_install
Copies file-related callbacks from the host table into the current runtime context.
@luce_rt_sockets_install
Copies network callbacks from the host table into the current runtime context.
@luce_rt_graphics_install
Copies window and graphics callbacks from the host table into the current runtime context.
!prof
Attaches branch-probability metadata so LLVM can place common and failure paths efficiently.

; ModuleID = '/Users/sedov/Dev/luciaos/www/lucelang/examples/closures.luc'
source_filename = "/Users/sedov/Dev/luciaos/www/lucelang/examples/closures.luc"
target triple = "arm64-apple-darwin24.6.0"

@luce.text.0 = private unnamed_addr constant [0 x i8] zeroinitializer
@luce.text.1 = private unnamed_addr constant [21 x i8] c"null object reference"
@luce.text.2 = private unnamed_addr constant [22 x i8] c"object used after free"
@luce.text.3 = private unnamed_addr constant [19 x i8] c"call depth exceeded"
@luce.function_table = private constant [3 x ptr] [ptr null, ptr null, ptr @luce.bound.2]
@luce.text.4 = private unnamed_addr constant [24 x i8] c"host service unavailable"
@luce.text.5 = private unnamed_addr constant [16 x i8] c"integer overflow"
@luce.text.6 = private unnamed_addr constant [10 x i8] c"make_adder"
@luce.text.7 = private unnamed_addr constant [59 x i8] c"/Users/sedov/Dev/luciaos/www/lucelang/examples/closures.luc"
@luce.origins.0 = private constant [13 x { i32, i32 }] [{ i32, i32 } { i32 2, i32 5 }, { i32, i32 } { i32 2, i32 5 }, { i32, i32 } { i32 2, i32 5 }, { i32, i32 } { i32 2, i32 5 }, { i32, i32 } { i32 4, i32 5 }, { i32, i32 } { i32 4, i32 5 }, { i32, i32 } { i32 4, i32 5 }, { i32, i32 } { i32 4, i32 5 }, { i32, i32 } { i32 4, i32 5 }, { i32, i32 } { i32 4, i32 5 }, { i32, i32 } { i32 4, i32 5 }, { i32, i32 } { i32 4, i32 5 }, { i32, i32 } { i32 4, i32 5 }]
@luce.text.8 = private unnamed_addr constant [4 x i8] c"main"
@luce.origins.1 = private constant [19 x { i32, i32 }] [{ i32, i32 } { i32 7, i32 5 }, { i32, i32 } { i32 7, i32 5 }, { i32, i32 } { i32 7, i32 5 }, { i32, i32 } { i32 7, i32 5 }, { i32, i32 } { i32 8, i32 5 }, { i32, i32 } { i32 8, i32 5 }, { i32, i32 } { i32 8, i32 5 }, { i32, i32 } { i32 8, i32 5 }, { i32, i32 } { i32 8, i32 5 }, { i32, i32 } { i32 8, i32 5 }, { i32, i32 } { i32 8, i32 5 }, { i32, i32 } { i32 8, i32 5 }, { i32, i32 } { i32 8, i32 5 }, { i32, i32 } { i32 8, i32 5 }, { i32, i32 } { i32 8, i32 5 }, { i32, i32 } { i32 8, i32 5 }, { i32, i32 } { i32 8, i32 5 }, { i32, i32 } { i32 8, i32 5 }, { i32, i32 } { i32 8, i32 5 }]
@luce.text.9 = private unnamed_addr constant [25 x i8] c"make_adder.(closure@2.33)"
@luce.origins.2 = private constant [7 x { i32, i32 }] [{ i32, i32 } { i32 3, i32 16 }, { i32, i32 } { i32 3, i32 16 }, { i32, i32 } { i32 3, i32 16 }, { i32, i32 } { i32 3, i32 9 }, { i32, i32 } { i32 3, i32 9 }, { i32, i32 } { i32 3, i32 9 }, { i32, i32 } { i32 3, i32 9 }]
@luce.functions = private constant [3 x { ptr, i64, ptr, i64, ptr, i64 }] [{ ptr, i64, ptr, i64, ptr, i64 } { ptr @luce.text.6, i64 10, ptr @luce.text.7, i64 59, ptr @luce.origins.0, i64 13 }, { ptr, i64, ptr, i64, ptr, i64 } { ptr @luce.text.8, i64 4, ptr @luce.text.7, i64 59, ptr @luce.origins.1, i64 19 }, { ptr, i64, ptr, i64, ptr, i64 } { ptr @luce.text.9, i64 25, ptr @luce.text.7, i64 59, ptr @luce.origins.2, i64 7 }]
@luce_artifact = constant { i64, i64, i64, i32, i32, i32, i32, { i32, [52 x i8] } } { i64 23734338332087628, i64 0, i64 -7092229304759745108, i32 3, i32 29, i32 1, i32 0, { i32, [52 x i8] } { i32 18, [52 x i8] c"aarch64-macos-none\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00" } }

define internal i32 @luce.0.make_adder(ptr align 8 nocapture readonly nonnull dereferenceable(472) noundef %0, ptr align 8 nocapture nonnull noundef %1, i64 noundef %2, i64 %3, ptr align 8 nocapture nonnull dereferenceable(8) writeonly noundef %4) {
5:
  %6 = alloca i64, align 8
  %7 = alloca { i8, i8, [6 x i8], i64, i64 }, align 8
  %8 = alloca { i8, i8, [6 x i8], i64, i64 }, align 8
  store i64 %3, ptr %6, align 8
  %9 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %7, i32 0, i32 0
  store i8 12, ptr %9, align 1
  %10 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %7, i32 0, i32 4
  store i64 2, ptr %10, align 8
  %11 = ptrtoint ptr null to i64
  %12 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %7, i32 0, i32 3
  store i64 %11, ptr %12, align 8
  %13 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %8, i32 0, i32 0
  store i8 12, ptr %13, align 1
  %14 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %8, i32 0, i32 4
  store i64 2, ptr %14, align 8
  %15 = ptrtoint ptr null to i64
  %16 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %8, i32 0, i32 3
  store i64 %15, ptr %16, align 8
  %17 = alloca { i8, i8, [6 x i8], i64, i64 },i64 1, align 8
  %18 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %17, i64 0
  %19 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %18, i32 0, i32 0
  store i8 2, ptr %19, align 1
  %20 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %18, i32 0, i32 4
  store i64 0, ptr %20, align 8
  %21 = alloca { i8, i8, [6 x i8], i64, i64 }, align 8
  %22 = alloca { i8, i8, [6 x i8], i64, i64 },i64 2, align 8
  %23 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %22, i64 0
  %24 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %23, i32 0, i32 0
  store i8 7, ptr %24, align 1
  %25 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %23, i32 0, i32 4
  store i64 0, ptr %25, align 8
  %26 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %22, i64 1
  %27 = alloca { i8, i8, [6 x i8], i64, i64 }, align 8
  %28 = alloca { i8, i8, [6 x i8], i64, i64 }, align 8
  %29 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %28, i32 0, i32 0
  store i8 12, ptr %29, align 1
  %30 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %28, i32 0, i32 4
  store i64 2, ptr %30, align 8
  %31 = alloca { i8, i8, [6 x i8], i64, i64 }, align 8
  %32 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %31, i32 0, i32 0
  store i8 12, ptr %32, align 1
  %33 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %31, i32 0, i32 4
  store i64 2, ptr %33, align 8
  %34 = alloca { i8, i8, [6 x i8], i64, i64 }, align 8
  %35 = alloca { i8, i8, [6 x i8], i64, i64 }, align 8
  %36 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %35, i32 0, i32 0
  store i8 12, ptr %36, align 1
  %37 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %35, i32 0, i32 4
  store i64 2, ptr %37, align 8
  %38 = alloca { i8, i8, [6 x i8], i64, i64 }, align 8
  br label %39

39:
  %40 = load i64, ptr %6, align 8
  %41 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %18, i32 0, i32 3
  store i64 %40, ptr %41, align 8
  %42 = call i32 @luce_rt_class_make(ptr %1, i64 0, i64 -1, ptr %17, i64 1, ptr %21)
  %43 = icmp ne i32 %42, 0
  br i1 %43, label %44, label %45, !prof !0

44:
  call void @luce_rt_unwound(ptr %1, i32 0, i32 1)
  ret i32 1

45:
  %46 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %21, i32 0, i32 3
  %47 = load i64, ptr %46, align 8
  %48 = zext i32 2 to i64
  %49 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %23, i32 0, i32 3
  store i64 %48, ptr %49, align 8
  call void @llvm.memcpy.inline.p0.p0.i64(ptr align 8 %26, ptr align 8 %21, i64 24, i1 false)
  %50 = call i32 @luce_rt_function_make(ptr %1, ptr %22, i64 2, ptr %27)
  %51 = icmp ne i32 %50, 0
  br i1 %51, label %52, label %53, !prof !0

52:
  call void @luce_rt_unwound(ptr %1, i32 0, i32 2)
  ret i32 1

53:
  %54 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %27, i32 0, i32 3
  %55 = load i64, ptr %54, align 8
  %56 = inttoptr i64 %55 to ptr
  call void @llvm.memcpy.inline.p0.p0.i64(ptr align 8 %8, ptr align 8 %27, i64 24, i1 false)
  %57 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %8, i32 0, i32 3
  %58 = load i64, ptr %57, align 8
  %59 = inttoptr i64 %58 to ptr
  %60 = ptrtoint ptr %59 to i64
  %61 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %28, i32 0, i32 3
  store i64 %60, ptr %61, align 8
  %62 = call i32 @luce_rt_retain(ptr %1, ptr %28)
  %63 = icmp ne i32 %62, 0
  br i1 %63, label %64, label %65, !prof !0

64:
  call void @luce_rt_unwound(ptr %1, i32 0, i32 5)
  ret i32 1

65:
  %66 = ptrtoint ptr %59 to i64
  %67 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %31, i32 0, i32 3
  store i64 %66, ptr %67, align 8
  %68 = call i32 @luce_rt_own_storage(ptr %1, ptr %31, ptr %34)
  %69 = icmp ne i32 %68, 0
  br i1 %69, label %70, label %71, !prof !0

70:
  call void @luce_rt_unwound(ptr %1, i32 0, i32 6)
  ret i32 1

71:
  %72 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %34, i32 0, i32 3
  %73 = load i64, ptr %72, align 8
  %74 = inttoptr i64 %73 to ptr
  %75 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %8, i32 0, i32 3
  %76 = load i64, ptr %75, align 8
  %77 = inttoptr i64 %76 to ptr
  %78 = ptrtoint ptr %77 to i64
  %79 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %35, i32 0, i32 3
  store i64 %78, ptr %79, align 8
  %80 = call i32 @luce_rt_release(ptr %1, ptr %35)
  %81 = icmp ne i32 %80, 0
  br i1 %81, label %82, label %83, !prof !0

82:
  call void @luce_rt_unwound(ptr %1, i32 0, i32 8)
  ret i32 1

83:
  %84 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %8, i32 0, i32 3
  %85 = load i64, ptr %84, align 8
  %86 = inttoptr i64 %85 to ptr
  call void @luce_rt_drop_storage(ptr %1, ptr %8, ptr %38)
  %87 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %38, i32 0, i32 3
  %88 = load i64, ptr %87, align 8
  %89 = inttoptr i64 %88 to ptr
  call void @llvm.memcpy.inline.p0.p0.i64(ptr align 8 %8, ptr align 8 %38, i64 24, i1 false)
  store ptr %74, ptr %4, align 8
  ret i32 0
}

define internal i32 @luce.1.main(ptr align 8 nocapture readonly nonnull dereferenceable(472) noundef %0, ptr align 8 nocapture nonnull noundef %1, i64 noundef %2, i64 %3) {
4:
  %5 = alloca i64, align 8
  %6 = alloca { i8, i8, [6 x i8], i64, i64 }, align 8
  %7 = alloca { i8, i8, [6 x i8], i64, i64 }, align 8
  %8 = alloca { i8, i8, [6 x i8], i64, i64 }, align 8
  store i64 %3, ptr %5, align 8
  %9 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %6, i32 0, i32 0
  store i8 12, ptr %9, align 1
  %10 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %6, i32 0, i32 4
  store i64 2, ptr %10, align 8
  %11 = ptrtoint ptr null to i64
  %12 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %6, i32 0, i32 3
  store i64 %11, ptr %12, align 8
  %13 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %7, i32 0, i32 0
  store i8 12, ptr %13, align 1
  %14 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %7, i32 0, i32 4
  store i64 2, ptr %14, align 8
  %15 = ptrtoint ptr null to i64
  %16 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %7, i32 0, i32 3
  store i64 %15, ptr %16, align 8
  %17 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %8, i32 0, i32 0
  store i8 4, ptr %17, align 1
  %18 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %8, i32 0, i32 1
  store i8 -1, ptr %18, align 1
  %19 = extractvalue { ptr, i64 } { ptr @luce.text.0, i64 0 }, 0
  %20 = ptrtoint ptr %19 to i64
  %21 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %8, i32 0, i32 3
  store i64 %20, ptr %21, align 8
  %22 = extractvalue { ptr, i64 } { ptr @luce.text.0, i64 0 }, 1
  %23 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %8, i32 0, i32 4
  store i64 %22, ptr %23, align 8
  %24 = sub nsw i64 %2, 1
  %25 = alloca ptr, align 8
  %26 = alloca i64, align 8
  %27 = alloca { i8, i8, [6 x i8], i64, i64 }, align 8
  %28 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %27, i32 0, i32 0
  store i8 2, ptr %28, align 1
  %29 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %27, i32 0, i32 4
  store i64 0, ptr %29, align 8
  %30 = alloca { i8, i8, [6 x i8], i64, i64 }, align 8
  %31 = alloca { i8, i8, [6 x i8], i64, i64 }, align 8
  %32 = alloca { i8, i8, [6 x i8], i64, i64 }, align 8
  %33 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %32, i32 0, i32 0
  store i8 12, ptr %33, align 1
  %34 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %32, i32 0, i32 4
  store i64 2, ptr %34, align 8
  %35 = alloca { i8, i8, [6 x i8], i64, i64 }, align 8
  br label %36

36:
  %37 = load i64, ptr %5, align 8
  %38 = trunc i64 %37 to i32
  %39 = lshr i64 %37, 32
  %40 = trunc i64 %39 to i32
  %41 = icmp eq i32 %38, -1
  br i1 %41, label %42, label %45, !prof !0

42:
  %43 = extractvalue { ptr, i64 } { ptr @luce.text.1, i64 21 }, 0
  %44 = extractvalue { ptr, i64 } { ptr @luce.text.1, i64 21 }, 1
  call void @luce_rt_raise(ptr %1, i32 14, ptr %43, i64 %44)
  call void @luce_rt_unwound(ptr %1, i32 1, i32 1)
  ret i32 1

45:
  %46 = getelementptr inbounds i8, ptr %1, i64 96
  %47 = load ptr, ptr %46, align 8!alias.scope !1, !noalias !2
  %48 = zext i32 %38 to i64
  %49 = mul nsw i64 %48, 112
  %50 = getelementptr inbounds i8, ptr %47, i64 %49
  %51 = getelementptr inbounds i8, ptr %50, i64 96
  %52 = load i32, ptr %51, align 4, !alias.scope !1, !noalias !2
  %53 = icmp ne i32 %52, %40
  br i1 %53, label %54, label %57, !prof !0

54:
  %55 = extractvalue { ptr, i64 } { ptr @luce.text.2, i64 22 }, 0
  %56 = extractvalue { ptr, i64 } { ptr @luce.text.2, i64 22 }, 1
  call void @luce_rt_raise(ptr %1, i32 13, ptr %55, i64 %56)
  call void @luce_rt_unwound(ptr %1, i32 1, i32 1)
  ret i32 1

57:
  %58 = and i32 %52, 1
  %59 = icmp ne i32 %58, 0
  br i1 %59, label %60, label %63, !prof !0

60:
  %61 = extractvalue { ptr, i64 } { ptr @luce.text.2, i64 22 }, 0
  %62 = extractvalue { ptr, i64 } { ptr @luce.text.2, i64 22 }, 1
  call void @luce_rt_raise(ptr %1, i32 13, ptr %61, i64 %62)
  call void @luce_rt_unwound(ptr %1, i32 1, i32 1)
  ret i32 1

63:
  %64 = getelementptr inbounds i8, ptr %50, i64 16
  %65 = load i64, ptr %64, align 8!alias.scope !1, !noalias !2
  %66 = load ptr, ptr %50, align 8, !alias.scope !1, !noalias !2
  %67 = icmp slt i64 %24, 1
  br i1 %67, label %68, label %71, !prof !0

68:
  %69 = extractvalue { ptr, i64 } { ptr @luce.text.3, i64 19 }, 0
  %70 = extractvalue { ptr, i64 } { ptr @luce.text.3, i64 19 }, 1
  call void @luce_rt_raise(ptr %1, i32 6, ptr %69, i64 %70)
  call void @luce_rt_unwound(ptr %1, i32 1, i32 2)
  ret i32 1

71:
  %72 = call i32 @luce.0.make_adder(ptr %0, ptr %1, i64 %24, i64 %65, ptr %25)
  %73 = icmp ne i32 %72, 0
  br i1 %73, label %74, label %75, !prof !0

74:
  call void @luce_rt_unwound(ptr %1, i32 1, i32 2)
  ret i32 1

75:
  %76 = load ptr, ptr %25, align 8
  %77 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %7, i32 0, i32 0
  store i8 12, ptr %77, align 1
  %78 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %7, i32 0, i32 4
  store i64 2, ptr %78, align 8
  %79 = ptrtoint ptr %76 to i64
  %80 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %7, i32 0, i32 3
  store i64 %79, ptr %80, align 8
  %81 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %7, i32 0, i32 3
  %82 = load i64, ptr %81, align 8
  %83 = inttoptr i64 %82 to ptr
  %84 = icmp slt i64 %24, 1
  br i1 %84, label %85, label %88, !prof !0

85:
  %86 = extractvalue { ptr, i64 } { ptr @luce.text.3, i64 19 }, 0
  %87 = extractvalue { ptr, i64 } { ptr @luce.text.3, i64 19 }, 1
  call void @luce_rt_raise(ptr %1, i32 6, ptr %86, i64 %87)
  call void @luce_rt_unwound(ptr %1, i32 1, i32 6)
  ret i32 1

88:
  %89 = ptrtoint ptr %83 to i64
  %90 = icmp eq i64 %89, 0
  br i1 %90, label %91, label %94, !prof !0

91:
  %92 = extractvalue { ptr, i64 } { ptr @luce.text.1, i64 21 }, 0
  %93 = extractvalue { ptr, i64 } { ptr @luce.text.1, i64 21 }, 1
  call void @luce_rt_raise(ptr %1, i32 14, ptr %92, i64 %93)
  call void @luce_rt_unwound(ptr %1, i32 1, i32 6)
  ret i32 1

94:
  %95 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %83, i64 0
  %96 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %95, i32 0, i32 3
  %97 = load i64, ptr %96, align 8
  %98 = trunc i64 %97 to i32
  %99 = icmp uge i32 %98, 3
  br i1 %99, label %100, label %103, !prof !0

100:
  %101 = extractvalue { ptr, i64 } { ptr @luce.text.1, i64 21 }, 0
  %102 = extractvalue { ptr, i64 } { ptr @luce.text.1, i64 21 }, 1
  call void @luce_rt_raise(ptr %1, i32 14, ptr %101, i64 %102)
  call void @luce_rt_unwound(ptr %1, i32 1, i32 6)
  ret i32 1

103:
  %104 = zext i32 %98 to i64
  %105 = getelementptr inbounds ptr, ptr @luce.function_table, i64 %104
  %106 = load ptr, ptr %105, align 8
  %107 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %83, i64 1
  %108 = call i32 %106(ptr %0, ptr %1, i64 %24, ptr %107, i64 2, ptr %26)
  %109 = icmp ne i32 %108, 0
  br i1 %109, label %110, label %111, !prof !0

110:
  call void @luce_rt_unwound(ptr %1, i32 1, i32 6)
  ret i32 1

111:
  %112 = load i64, ptr %26, align 8
  %113 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %27, i32 0, i32 3
  store i64 %112, ptr %113, align 8
  %114 = call i32 @luce_rt_str(ptr %1, ptr %27, ptr %30)
  %115 = icmp ne i32 %114, 0
  br i1 %115, label %116, label %117, !prof !0

116:
  call void @luce_rt_unwound(ptr %1, i32 1, i32 7)
  ret i32 1

117:
  %118 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %30, i32 0, i32 3
  %119 = load i64, ptr %118, align 8
  %120 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %30, i32 0, i32 1
  %121 = load i8, ptr %120, align 1
  %122 = icmp eq i8 %121, -1
  %123 = inttoptr i64 %119 to ptr
  %124 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %30, i32 0, i32 2
  %125 = select i1 %122, ptr %123, ptr %124
  %126 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %30, i32 0, i32 4
  %127 = load i64, ptr %126, align 8
  %128 = zext i8 %121 to i64
  %129 = select i1 %122, i64 %127, i64 %128
  %130 = insertvalue { ptr, i64 } poison, ptr %125, 0
  %131 = insertvalue { ptr, i64 } %130, i64 %129, 1
  call void @llvm.memcpy.inline.p0.p0.i64(ptr align 8 %8, ptr align 8 %30, i64 24, i1 false)
  %132 = extractvalue { ptr, i64 } %131, 0
  %133 = extractvalue { ptr, i64 } %131, 1
  %134 = getelementptr inbounds { ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr }, ptr %0, i32 0, i32 1
  %135 = load ptr, ptr %134, align 8
  %136 = icmp eq ptr %135, null
  br i1 %136, label %137, label %140, !prof !0

137:
  %138 = extractvalue { ptr, i64 } { ptr @luce.text.4, i64 24 }, 0
  %139 = extractvalue { ptr, i64 } { ptr @luce.text.4, i64 24 }, 1
  call void @luce_rt_raise(ptr %1, i32 9, ptr %138, i64 %139)
  call void @luce_rt_unwound(ptr %1, i32 1, i32 9)
  ret i32 1

140:
  %141 = getelementptr inbounds { ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr }, ptr %0, i32 0, i32 0
  %142 = load ptr, ptr %141, align 8
  %143 = call i32 %135(ptr %142, ptr %132, i64 %133)
  %144 = icmp eq i32 %143, -1
  br i1 %144, label %145, label %146, !prof !0

145:
  call void @luce_rt_exhaust(ptr %1)
  ret i32 1

146:
  %147 = icmp ne i32 %143, 0
  %148 = icmp ne i32 %143, 1
  %149 = and i1 %147, %148
  br i1 %149, label %150, label %153, !prof !0

150:
  %151 = extractvalue { ptr, i64 } { ptr @luce.text.4, i64 24 }, 0
  %152 = extractvalue { ptr, i64 } { ptr @luce.text.4, i64 24 }, 1
  call void @luce_rt_raise(ptr %1, i32 9, ptr %151, i64 %152)
  call void @luce_rt_unwound(ptr %1, i32 1, i32 9)
  ret i32 1

153:
  %154 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %8, i32 0, i32 3
  %155 = load i64, ptr %154, align 8
  %156 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %8, i32 0, i32 1
  %157 = load i8, ptr %156, align 1
  %158 = icmp eq i8 %157, -1
  %159 = inttoptr i64 %155 to ptr
  %160 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %8, i32 0, i32 2
  %161 = select i1 %158, ptr %159, ptr %160
  %162 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %8, i32 0, i32 4
  %163 = load i64, ptr %162, align 8
  %164 = zext i8 %157 to i64
  %165 = select i1 %158, i64 %163, i64 %164
  %166 = insertvalue { ptr, i64 } poison, ptr %161, 0
  %167 = insertvalue { ptr, i64 } %166, i64 %165, 1
  call void @luce_rt_drop_storage(ptr %1, ptr %8, ptr %31)
  %168 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %31, i32 0, i32 3
  %169 = load i64, ptr %168, align 8
  %170 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %31, i32 0, i32 1
  %171 = load i8, ptr %170, align 1
  %172 = icmp eq i8 %171, -1
  %173 = inttoptr i64 %169 to ptr
  %174 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %31, i32 0, i32 2
  %175 = select i1 %172, ptr %173, ptr %174
  %176 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %31, i32 0, i32 4
  %177 = load i64, ptr %176, align 8
  %178 = zext i8 %171 to i64
  %179 = select i1 %172, i64 %177, i64 %178
  %180 = insertvalue { ptr, i64 } poison, ptr %175, 0
  %181 = insertvalue { ptr, i64 } %180, i64 %179, 1
  call void @llvm.memcpy.inline.p0.p0.i64(ptr align 8 %8, ptr align 8 %31, i64 24, i1 false)
  %182 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %7, i32 0, i32 3
  %183 = load i64, ptr %182, align 8
  %184 = inttoptr i64 %183 to ptr
  %185 = ptrtoint ptr %184 to i64
  %186 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %32, i32 0, i32 3
  store i64 %185, ptr %186, align 8
  %187 = call i32 @luce_rt_release(ptr %1, ptr %32)
  %188 = icmp ne i32 %187, 0
  br i1 %188, label %189, label %190, !prof !0

189:
  call void @luce_rt_unwound(ptr %1, i32 1, i32 14)
  ret i32 1

190:
  %191 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %7, i32 0, i32 3
  %192 = load i64, ptr %191, align 8
  %193 = inttoptr i64 %192 to ptr
  call void @luce_rt_drop_storage(ptr %1, ptr %7, ptr %35)
  %194 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %35, i32 0, i32 3
  %195 = load i64, ptr %194, align 8
  %196 = inttoptr i64 %195 to ptr
  call void @llvm.memcpy.inline.p0.p0.i64(ptr align 8 %7, ptr align 8 %35, i64 24, i1 false)
  ret i32 0
}

define internal i32 @"luce.2.make_adder.(closure@2.33)"(ptr align 8 nocapture readonly nonnull dereferenceable(472) noundef %0, ptr align 8 nocapture nonnull noundef %1, i64 noundef %2, i64 %3, i64 %4, ptr align 8 nocapture nonnull dereferenceable(8) writeonly noundef %5) {
6:
  %7 = alloca i64, align 8
  %8 = alloca i64, align 8
  %9 = alloca i64, align 8
  store i64 %3, ptr %7, align 8
  store i64 %4, ptr %8, align 8
  store i64 0, ptr %9, align 8
  %10 = alloca { i8, i8, [6 x i8], i64, i64 }, align 8
  %11 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %10, i32 0, i32 0
  store i8 6, ptr %11, align 1
  %12 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %10, i32 0, i32 4
  store i64 0, ptr %12, align 8
  %13 = alloca { i8, i8, [6 x i8], i64, i64 }, align 8
  br label %14

14:
  %15 = load i64, ptr %7, align 8
  %16 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %10, i32 0, i32 3
  store i64 %15, ptr %16, align 8
  %17 = call i32 @luce_rt_class_get(ptr %1, ptr %10, i64 0, i64 0, ptr %13)
  %18 = icmp ne i32 %17, 0
  br i1 %18, label %19, label %20, !prof !0

19:
  call void @luce_rt_unwound(ptr %1, i32 2, i32 1)
  ret i32 1

20:
  %21 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %13, i32 0, i32 3
  %22 = load i64, ptr %21, align 8
  store i64 %22, ptr %9, align 8
  %23 = load i64, ptr %9, align 8
  %24 = load i64, ptr %8, align 8
  %25 = call { i64, i1 } @llvm.sadd.with.overflow.i64(i64 %23, i64 %24)
  %26 = extractvalue { i64, i1 } %25, 0
  %27 = extractvalue { i64, i1 } %25, 1
  br i1 %27, label %28, label %31, !prof !0

28:
  %29 = extractvalue { ptr, i64 } { ptr @luce.text.5, i64 16 }, 0
  %30 = extractvalue { ptr, i64 } { ptr @luce.text.5, i64 16 }, 1
  call void @luce_rt_raise(ptr %1, i32 0, ptr %29, i64 %30)
  call void @luce_rt_unwound(ptr %1, i32 2, i32 5)
  ret i32 1

31:
  store i64 %26, ptr %5, align 8
  ret i32 0
}

define internal i32 @luce.bound.2(ptr %0, ptr %1, i64 %2, ptr %3, i64 %4, ptr %5) {
6:
  %7 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %3, i32 0, i32 3
  %8 = load i64, ptr %7, align 8
  %9 = call i32 @"luce.2.make_adder.(closure@2.33)"(ptr %0, ptr %1, i64 %2, i64 %8, i64 %4, ptr %5)
  ret i32 %9
}

; Function Attrs: nounwind memory(readwrite)
declare i32 @luce_rt_class_make(ptr nocapture nonnull noundef %0, i64 %1, i64 %2, ptr align 8 nocapture readonly nonnull noundef %3, i64 %4, ptr align 8 nocapture nonnull dereferenceable(24) writeonly noundef %5) #0

; Function Attrs: nounwind cold willreturn memory(argmem: readwrite, inaccessiblemem: readwrite)
declare void @luce_rt_unwound(ptr nocapture nonnull noundef %0, i32 %1, i32 %2) #1

; Function Attrs: nounwind willreturn nofree nocallback memory(argmem: readwrite)
declare void @llvm.memcpy.inline.p0.p0.i64(ptr noalias nocapture writeonly %0, ptr noalias nocapture readonly %1, i64 %2, i1 immarg %3) #2

; Function Attrs: nounwind willreturn memory(argmem: readwrite, inaccessiblemem: readwrite)
declare i32 @luce_rt_function_make(ptr nocapture nonnull noundef %0, ptr align 8 nocapture readonly nonnull noundef %1, i64 %2, ptr align 8 nocapture nonnull dereferenceable(24) writeonly noundef %3) #3

; Function Attrs: nounwind willreturn memory(readwrite)
declare i32 @luce_rt_retain(ptr nocapture nonnull noundef %0, ptr align 8 nocapture readonly nonnull dereferenceable(24) noundef %1) #4

; Function Attrs: nounwind willreturn memory(argmem: readwrite, inaccessiblemem: readwrite)
declare i32 @luce_rt_own_storage(ptr nocapture nonnull noundef %0, ptr align 8 nocapture readonly nonnull dereferenceable(24) noundef %1, ptr align 8 nocapture nonnull dereferenceable(24) writeonly noundef %2) #3

; Function Attrs: nounwind memory(readwrite)
declare i32 @luce_rt_release(ptr nocapture nonnull noundef %0, ptr align 8 nocapture readonly nonnull dereferenceable(24) noundef %1) #0

; Function Attrs: nounwind willreturn memory(argmem: readwrite, inaccessiblemem: readwrite)
declare void @luce_rt_drop_storage(ptr nocapture nonnull noundef %0, ptr align 8 nocapture readonly nonnull dereferenceable(24) noundef %1, ptr align 8 nocapture nonnull dereferenceable(24) writeonly noundef %2) #3

; Function Attrs: nounwind cold willreturn memory(argmem: readwrite, inaccessiblemem: readwrite)
declare void @luce_rt_raise(ptr nocapture nonnull noundef %0, i32 %1, ptr nocapture readonly %2, i64 %3) #1

; Function Attrs: nounwind willreturn memory(read, argmem: readwrite, inaccessiblemem: readwrite)
declare i32 @luce_rt_str(ptr nocapture nonnull noundef %0, ptr align 8 nocapture readonly nonnull dereferenceable(24) noundef %1, ptr align 8 nocapture nonnull dereferenceable(24) writeonly noundef %2) #5

; Function Attrs: nounwind cold willreturn memory(argmem: write)
declare void @luce_rt_exhaust(ptr nocapture nonnull noundef %0) #6

; Function Attrs: nounwind willreturn memory(read, argmem: readwrite)
declare i32 @luce_rt_class_get(ptr nocapture nonnull noundef %0, ptr align 8 nocapture readonly nonnull dereferenceable(24) noundef %1, i64 %2, i64 %3, ptr align 8 nocapture nonnull dereferenceable(24) writeonly noundef %4) #7

; Function Attrs: nounwind speculatable willreturn nofree nosync nocallback memory(none)
declare { i64, i1 } @llvm.sadd.with.overflow.i64(i64 %0, i64 %1) #8

define i32 @luce_main(ptr align 8 nocapture readonly nonnull dereferenceable(472) noundef %0) {
1:
  %2 = alloca i64, align 8
  %3 = alloca i32, align 8
  store i64 256, ptr %2, align 8
  %4 = getelementptr inbounds { ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr }, ptr %0, i32 0, i32 0
  %5 = load ptr, ptr %4, align 8
  %6 = getelementptr inbounds { ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr }, ptr %0, i32 0, i32 14
  %7 = load ptr, ptr %6, align 8
  %8 = icmp eq ptr %7, null
  br i1 %8, label %11, label %9

9:
  %10 = call i64 %7(ptr %5)
  store i64 %10, ptr %2, align 8
  br label %11

11:
  %12 = load i64, ptr %2, align 8
  %13 = call ptr @luce_rt_open(ptr @luce.functions, i64 3)
  %14 = icmp eq ptr %13, null
  br i1 %14, label %15, label %16, !prof !0

15:
  ret i32 2

16:
  %17 = getelementptr inbounds { ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr }, ptr %0, i32 0, i32 28
  %18 = load ptr, ptr %17, align 8
  %19 = getelementptr inbounds { ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr }, ptr %0, i32 0, i32 54
  %20 = load ptr, ptr %19, align 8
  %21 = getelementptr inbounds { ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr }, ptr %0, i32 0, i32 55
  %22 = load ptr, ptr %21, align 8
  %23 = getelementptr inbounds { ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr }, ptr %0, i32 0, i32 56
  %24 = load ptr, ptr %23, align 8
  %25 = getelementptr inbounds { ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr }, ptr %0, i32 0, i32 57
  %26 = load ptr, ptr %25, align 8
  %27 = getelementptr inbounds { ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr }, ptr %0, i32 0, i32 58
  %28 = load ptr, ptr %27, align 8
  %29 = getelementptr inbounds { ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr }, ptr %0, i32 0, i32 29
  %30 = load ptr, ptr %29, align 8
  %31 = getelementptr inbounds { ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr }, ptr %0, i32 0, i32 30
  %32 = load ptr, ptr %31, align 8
  %33 = getelementptr inbounds { ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr }, ptr %0, i32 0, i32 31
  %34 = load ptr, ptr %33, align 8
  %35 = getelementptr inbounds { ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr }, ptr %0, i32 0, i32 32
  %36 = load ptr, ptr %35, align 8
  call void @luce_rt_files_install(ptr %13, ptr %5, ptr %18, ptr %20, ptr %22, ptr %24, ptr %26, ptr %28, ptr %30, ptr %32, ptr %34, ptr %36)
  %37 = getelementptr inbounds { ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr }, ptr %0, i32 0, i32 48
  %38 = load ptr, ptr %37, align 8
  %39 = getelementptr inbounds { ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr }, ptr %0, i32 0, i32 49
  %40 = load ptr, ptr %39, align 8
  %41 = getelementptr inbounds { ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr }, ptr %0, i32 0, i32 50
  %42 = load ptr, ptr %41, align 8
  %43 = getelementptr inbounds { ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr }, ptr %0, i32 0, i32 51
  %44 = load ptr, ptr %43, align 8
  %45 = getelementptr inbounds { ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr }, ptr %0, i32 0, i32 52
  %46 = load ptr, ptr %45, align 8
  call void @luce_rt_sockets_install(ptr %13, ptr %5, ptr %38, ptr %40, ptr %42, ptr %44, ptr %46)
  %47 = getelementptr inbounds { ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr }, ptr %0, i32 0, i32 40
  %48 = load ptr, ptr %47, align 8
  %49 = getelementptr inbounds { ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr }, ptr %0, i32 0, i32 41
  %50 = load ptr, ptr %49, align 8
  %51 = getelementptr inbounds { ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr }, ptr %0, i32 0, i32 42
  %52 = load ptr, ptr %51, align 8
  %53 = getelementptr inbounds { ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr }, ptr %0, i32 0, i32 43
  %54 = load ptr, ptr %53, align 8
  %55 = getelementptr inbounds { ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr }, ptr %0, i32 0, i32 44
  %56 = load ptr, ptr %55, align 8
  %57 = getelementptr inbounds { ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr }, ptr %0, i32 0, i32 45
  %58 = load ptr, ptr %57, align 8
  %59 = getelementptr inbounds { ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr }, ptr %0, i32 0, i32 46
  %60 = load ptr, ptr %59, align 8
  %61 = getelementptr inbounds { ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr }, ptr %0, i32 0, i32 47
  %62 = load ptr, ptr %61, align 8
  call void @luce_rt_graphics_install(ptr %13, ptr %5, ptr %48, ptr %50, ptr %52, ptr %54, ptr %56, ptr %58, ptr %60, ptr %62)
  %63 = icmp slt i64 %12, 1
  br i1 %63, label %64, label %65, !prof !0

64:
  call void @luce_rt_raise(ptr %13, i32 6, ptr @luce.text.3, i64 19)
  store i32 1, ptr %3, align 8
  br label %73

65:
  %66 = alloca { i8, i8, [6 x i8], i64, i64 }, align 8
  %67 = getelementptr inbounds { ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr }, ptr %0, i32 0, i32 4
  %68 = load ptr, ptr %67, align 8
  %69 = getelementptr inbounds { ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr }, ptr %0, i32 0, i32 5
  %70 = load ptr, ptr %69, align 8
  %71 = call i32 @luce_rt_args_list(ptr %13, ptr %5, ptr %68, ptr %70, ptr %66)
  %72 = icmp ne i32 %71, 0
  br i1 %72, label %77, label %78, !prof !0

73:
  %74 = load i32, ptr %3, align 8
  %75 = icmp eq i32 %74, 1
  %76 = icmp eq i32 %74, 2
  br i1 %75, label %83, label %86, !prof !0

77:
  store i32 1, ptr %3, align 8
  br label %73

78:
  %79 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %66, i32 0, i32 3
  %80 = load i64, ptr %79, align 8
  %81 = call i32 @luce.1.main(ptr %0, ptr %13, i64 %12, i64 %80)
  store i32 %81, ptr %3, align 8
  %82 = call i32 @luce_rt_release(ptr %13, ptr %66)
  br label %73

83:
  %84 = getelementptr inbounds { ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr }, ptr %0, i32 0, i32 2
  %85 = load ptr, ptr %84, align 8
  call void @luce_rt_report(ptr %13, ptr %5, ptr %85)
  br label %86

86:
  br i1 %76, label %87, label %90, !prof !0

87:
  %88 = getelementptr inbounds { ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr }, ptr %0, i32 0, i32 15
  %89 = load ptr, ptr %88, align 8
  call void @luce_rt_report_error(ptr %13, ptr %5, ptr %89)
  br label %90

90:
  %91 = call i32 @luce_rt_status(ptr %13, i32 %74)
  %92 = icmp eq i32 %91, 2
  %93 = getelementptr inbounds { ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr }, ptr %0, i32 0, i32 3
  %94 = load ptr, ptr %93, align 8
  %95 = icmp eq ptr %94, null
  %96 = or i1 %95, %92
  br i1 %96, label %97, label %98

97:
  call void @luce_rt_close(ptr %13)
  ret i32 %91

98:
  %99 = call i64 @luce_rt_leaked(ptr %13)
  call void %94(ptr %5, i64 %99)
  br label %97
}

; Function Attrs: nounwind willreturn memory(argmem: read, inaccessiblemem: readwrite)
declare noalias ptr @luce_rt_open(ptr readonly %0, i64 %1) #9

; Function Attrs: nounwind willreturn memory(argmem: readwrite)
declare void @luce_rt_files_install(ptr nocapture nonnull noundef %0, ptr %1, ptr %2, ptr %3, ptr %4, ptr %5, ptr %6, ptr %7, ptr %8, ptr %9, ptr %10, ptr %11) #10

; Function Attrs: nounwind willreturn memory(readwrite)
declare void @luce_rt_sockets_install(ptr nocapture nonnull noundef %0, ptr %1, ptr %2, ptr %3, ptr %4, ptr %5, ptr %6) #4

; Function Attrs: nounwind willreturn memory(argmem: readwrite)
declare void @luce_rt_graphics_install(ptr nocapture nonnull noundef %0, ptr %1, ptr %2, ptr %3, ptr %4, ptr %5, ptr %6, ptr %7, ptr %8, ptr %9) #10

; Function Attrs: nounwind memory(readwrite)
declare i32 @luce_rt_args_list(ptr nocapture nonnull noundef %0, ptr %1, ptr %2, ptr %3, ptr align 8 nocapture nonnull dereferenceable(24) writeonly noundef %4) #0

; Function Attrs: cold
declare void @luce_rt_report(ptr nocapture nonnull noundef %0, ptr %1, ptr %2) #11

; Function Attrs: cold
declare void @luce_rt_report_error(ptr nocapture nonnull noundef %0, ptr %1, ptr %2) #11

; Function Attrs: nounwind willreturn memory(argmem: read)
declare i32 @luce_rt_status(ptr nocapture nonnull noundef %0, i32 %1) #12

; Function Attrs: nounwind willreturn memory(argmem: read)
declare i64 @luce_rt_leaked(ptr nocapture nonnull noundef %0) #12

; Function Attrs: nounwind memory(readwrite)
declare void @luce_rt_close(ptr nocapture nonnull noundef %0) #0

attributes #0 = { nounwind memory(readwrite) }
attributes #1 = { nounwind cold willreturn memory(argmem: readwrite, inaccessiblemem: readwrite) }
attributes #2 = { nounwind willreturn nofree nocallback memory(argmem: readwrite) }
attributes #3 = { nounwind willreturn memory(argmem: readwrite, inaccessiblemem: readwrite) }
attributes #4 = { nounwind willreturn memory(readwrite) }
attributes #5 = { nounwind willreturn memory(read, argmem: readwrite, inaccessiblemem: readwrite) }
attributes #6 = { nounwind cold willreturn memory(argmem: write) }
attributes #7 = { nounwind willreturn memory(read, argmem: readwrite) }
attributes #8 = { nounwind speculatable willreturn nofree nosync nocallback memory(none) }
attributes #9 = { nounwind willreturn memory(argmem: read, inaccessiblemem: readwrite) }
attributes #10 = { nounwind willreturn memory(argmem: readwrite) }
attributes #11 = { cold }
attributes #12 = { nounwind willreturn memory(argmem: read) }

!0 = !{!"branch_weights", i32 1, i32 2000}
!1 = !{!3}
!2 = !{!4}
!3 = !{!"luce.rows", !5}
!4 = !{!"luce.elements", !5}
!5 = !{!"luce.alias"}

ARM64 object code. LLVM selected these instructions, registers, calls, and branch conditions for this target.

open assembly file
ARM64 instruction guide hover, focus, or tap dotted terms

x8 is a 64-bit register; w8 is its low 32 bits. A leading # marks a constant, brackets describe a memory address, and conditional instructions read the processor flags set by the preceding arithmetic or comparison.

Hover or focus a dotted term in the file for its explanation. On a touch screen, tap a term to keep the note open and tap elsewhere to close it. The list includes the operations that appear in this file.

mov
Copies a register value or loads a small constant. Calls also use it to place arguments in the required registers.
add
Adds registers or a constant. Address setup and stack restoration frequently use this instruction.
sub
Subtracts registers or a constant. Function prologues use it to reserve stack space.
adds
Adds and updates the negative, zero, carry, and overflow flags for a following conditional instruction.
cmp
Performs a subtraction solely to set condition flags; a following branch or select consumes those flags.
cmn
Performs an addition solely to set condition flags. The checked multiply-by-two path uses it to recognize unsafe inputs.
csel
Selects one of two registers from the current condition flags. The clamp uses it to choose the doubled value or limit.
ldr
Loads a register from memory using a scaled address offset.
str
Stores one register into memory using a scaled address offset.
ldp
Loads two adjacent registers, often restoring saved registers or reading neighboring fields.
stp
Stores two adjacent registers, often saving the caller's registers in a function prologue.
ldur
Loads from an unscaled byte offset, which is useful for stack slots below the frame pointer.
stur
Stores to an unscaled byte offset, which is useful for stack slots below the frame pointer.
ldrb
Loads one byte and widens it into a register.
strb
Stores the low byte of a register.
sturb
Stores one byte using an unscaled byte offset.
strh
Stores the low 16 bits of a register.
adrp
Loads the page address of a symbol. The linker fills in the final page-relative relocation.
bl
Calls a direct target and records the return address in x30.
blr
Calls the function address held in a register, as required for host callbacks and function values.
b
Jumps to another instruction address.
b.eq
Branches when the previous comparison reported equality.
b.ne
Branches when the previous comparison reported different values.
b.le
Branches when the signed left operand was smaller or equal.
b.hs
Branches when an unsigned comparison found higher-or-same, represented by a set carry flag.
b.vs
Branches when the arithmetic overflow flag is set.
cbz
Compares a register with zero and branches when it is zero.
cbnz
Compares a register with zero and branches when it contains a nonzero value.
tbnz
Tests one selected bit and branches when that bit is set; packed runtime flags use this form.
lsl
Shifts bits left. A shift by one multiplies by two after the overflow check has established a safe range.
lsr
Shifts bits right and fills with zero, often extracting the upper field of a packed handle.
umaddl
Widens two 32-bit unsigned operands, multiplies them, and adds a 64-bit base address.
orr
Combines bits, commonly setting tag or flag bits in a packed value.
and
Masks bits so later code can inspect a packed tag or flag.
ret
Returns to the address in x30 and ends the current machine function.


/Users/sedov/Dev/luciaos/www/lucelang/out/traces/closures.o:	file format mach-o arm64

Disassembly of section __TEXT,__text:

0000000000000000 <ltmp0>:
; luce.bound.2():
       0:      	sub	sp, sp, #0x60
       4:      	stp	x20, x19, [sp, #0x40]
       8:      	mov	x19, x1
       c:      	ldr	x9, [x3, #0x8]
      10:      	stp	x22, x21, [sp, #0x30]
      14:      	mov	x21, x4
      18:      	mov	w8, #0x6                ; =6
      1c:      	add	x1, sp, #0x18
      20:      	mov	x4, sp
      24:      	mov	x0, x19
      28:      	mov	x2, xzr
      2c:      	mov	x3, xzr
      30:      	stp	x29, x30, [sp, #0x50]
      34:      	mov	x20, x5
      38:      	strb	w8, [sp, #0x18]
      3c:      	stp	x9, xzr, [sp, #0x20]
      40:      	bl	0x40 <ltmp0+0x40>
      44:      	cbnz	w0, 0x70 <ltmp0+0x70>
      48:      	ldr	x8, [sp, #0x8]
      4c:      	adds	x8, x8, x21
      50:      	b.vs	0x80 <ltmp0+0x80>
      54:      	mov	w0, wzr
      58:      	str	x8, [x20]
      5c:      	ldp	x29, x30, [sp, #0x50]
      60:      	ldp	x20, x19, [sp, #0x40]
      64:      	ldp	x22, x21, [sp, #0x30]
      68:      	add	sp, sp, #0x60
      6c:      	ret
      70:      	mov	x0, x19
      74:      	mov	w1, #0x2                ; =2
      78:      	mov	w2, #0x1                ; =1
      7c:      	b	0xa4 <ltmp0+0xa4>
      80:      	adrp	x2, 0x0 <ltmp0>
      84:      	add	x2, x2, #0x0
      88:      	mov	x0, x19
      8c:      	mov	w1, wzr
      90:      	mov	w3, #0x10               ; =16
      94:      	bl	0x94 <ltmp0+0x94>
      98:      	mov	x0, x19
      9c:      	mov	w1, #0x2                ; =2
      a0:      	mov	w2, #0x5                ; =5
      a4:      	bl	0xa4 <ltmp0+0xa4>
      a8:      	mov	w0, #0x1                ; =1
      ac:      	ldp	x29, x30, [sp, #0x50]
      b0:      	ldp	x20, x19, [sp, #0x40]
      b4:      	ldp	x22, x21, [sp, #0x30]
      b8:      	add	sp, sp, #0x60
      bc:      	ret

00000000000000c0 <_luce_main>:
; luce_main():
      c0:      	stp	x28, x27, [sp, #-0x60]!
      c4:      	stp	x26, x25, [sp, #0x10]
      c8:      	stp	x24, x23, [sp, #0x20]
      cc:      	stp	x22, x21, [sp, #0x30]
      d0:      	stp	x20, x19, [sp, #0x40]
      d4:      	stp	x29, x30, [sp, #0x50]
      d8:      	add	x29, sp, #0x50
      dc:      	sub	sp, sp, #0x1b0
      e0:      	mov	x19, sp
      e4:      	ldr	x8, [x0, #0x70]
      e8:      	ldr	x20, [x0]
      ec:      	mov	x21, x0
      f0:      	cbz	x8, 0x460 <_luce_main+0x3a0>
      f4:      	mov	x0, x20
      f8:      	blr	x8
      fc:      	mov	x24, x0
     100:      	adrp	x0, 0x0 <ltmp0>
     104:      	add	x0, x0, #0x0
     108:      	mov	w1, #0x3                ; =3
     10c:      	bl	0x10c <_luce_main+0x4c>
     110:      	cbz	x0, 0x478 <_luce_main+0x3b8>
     114:      	ldp	x3, x4, [x21, #0x1b0]
     118:      	mov	x22, x0
     11c:      	ldp	x5, x6, [x21, #0x1c0]
     120:      	ldr	x2, [x21, #0xe0]
     124:      	ldp	x8, x9, [x21, #0xf8]
     128:      	ldr	x7, [x21, #0x1d0]
     12c:      	ldur	q0, [x21, #0xe8]
     130:      	sub	sp, sp, #0x20
     134:      	mov	x1, x20
     138:      	stp	x8, x9, [sp, #0x10]
     13c:      	str	q0, [sp]
     140:      	bl	0x140 <_luce_main+0x80>
     144:      	add	sp, sp, #0x20
     148:      	ldp	x2, x3, [x21, #0x180]
     14c:      	mov	x0, x22
     150:      	ldp	x4, x5, [x21, #0x190]
     154:      	mov	x1, x20
     158:      	ldr	x6, [x21, #0x1a0]
     15c:      	bl	0x15c <_luce_main+0x9c>
     160:      	ldp	x8, x9, [x21, #0x170]
     164:      	ldp	x2, x3, [x21, #0x140]
     168:      	ldp	x4, x5, [x21, #0x150]
     16c:      	ldp	x6, x7, [x21, #0x160]
     170:      	stp	x8, x9, [sp, #-0x10]!
     174:      	mov	x0, x22
     178:      	mov	x1, x20
     17c:      	bl	0x17c <_luce_main+0xbc>
     180:      	add	sp, sp, #0x10
     184:      	cmp	x24, #0x0
     188:      	b.le	0x4e8 <_luce_main+0x428>
     18c:      	sub	x23, sp, #0x20
     190:      	mov	sp, x23
     194:      	ldp	x2, x3, [x21, #0x20]
     198:      	mov	x0, x22
     19c:      	mov	x1, x20
     1a0:      	mov	x4, x23
     1a4:      	bl	0x1a4 <_luce_main+0xe4>
     1a8:      	cbnz	w0, 0x58c <_luce_main+0x4cc>
     1ac:      	mov	w9, #0xff04             ; =65284
     1b0:      	mov	w8, #0xc                ; =12
     1b4:      	mov	w10, #0x2               ; =2
     1b8:      	strh	w9, [x19, #0x80]
     1bc:      	adrp	x9, 0x0 <ltmp0>
     1c0:      	add	x9, x9, #0x0
     1c4:      	str	x9, [x19, #0x88]
     1c8:      	ldr	x9, [x23, #0x8]
     1cc:      	strb	w8, [x19, #0xa0]
     1d0:      	cmn	w9, #0x1
     1d4:      	str	x10, [x19, #0xb0]
     1d8:      	strb	w10, [x19, #0x60]
     1dc:      	str	xzr, [x19, #0x70]
     1e0:      	strb	w8, [x19, #0x18]
     1e4:      	str	x10, [x19, #0x28]
     1e8:      	b.eq	0x504 <_luce_main+0x444>
     1ec:      	mov	w8, #0x70               ; =112
     1f0:      	ldr	x10, [x22, #0x60]
     1f4:      	umaddl	x8, w9, w8, x10
     1f8:      	lsr	x9, x9, #32
     1fc:      	ldr	w10, [x8, #0x60]
     200:      	cmp	w10, w9
     204:      	b.ne	0x480 <_luce_main+0x3c0>
     208:      	tbnz	w9, #0x0, 0x480 <_luce_main+0x3c0>
     20c:      	cmp	x24, #0x1
     210:      	b.eq	0x52c <_luce_main+0x46c>
     214:      	mov	w10, #0x7               ; =7
     218:      	ldr	x8, [x8, #0x10]
     21c:      	mov	w9, #0x2                ; =2
     220:      	sturb	w10, [x29, #-0xd0]
     224:      	mov	w10, #0xc               ; =12
     228:      	sub	x3, x29, #0x88
     22c:      	sub	x5, x29, #0xa0
     230:      	mov	x0, x22
     234:      	mov	x1, xzr
     238:      	mov	x2, #-0x1               ; =-1
     23c:      	mov	w4, #0x1                ; =1
     240:      	sturb	w9, [x29, #-0x88]
     244:      	stur	xzr, [x29, #-0xc0]
     248:      	mov	w25, #0x1               ; =1
     24c:      	strb	w10, [x19, #0x100]
     250:      	str	x9, [x19, #0x110]
     254:      	strb	w10, [x19, #0xe8]
     258:      	str	x9, [x19, #0xf8]
     25c:      	strb	w10, [x19, #0xb8]
     260:      	str	x9, [x19, #0xc8]
     264:      	stp	x8, xzr, [x29, #-0x80]
     268:      	bl	0x268 <_luce_main+0x1a8>
     26c:      	cbnz	w0, 0x560 <_luce_main+0x4a0>
     270:      	ldur	q0, [x29, #-0xa0]
     274:      	ldur	x8, [x29, #-0x90]
     278:      	sub	x26, x29, #0xe8
     27c:      	mov	w25, #0x2               ; =2
     280:      	sub	x1, x29, #0xd0
     284:      	sub	x3, x29, #0xe8
     288:      	mov	x0, x22
     28c:      	mov	w2, #0x2                ; =2
     290:      	stur	q0, [x26, #0x30]
     294:      	stur	x25, [x29, #-0xc8]
     298:      	stur	x8, [x29, #-0xa8]
     29c:      	bl	0x29c <_luce_main+0x1dc>
     2a0:      	cbnz	w0, 0x548 <_luce_main+0x488>
     2a4:      	ldr	q0, [x26]
     2a8:      	ldur	x8, [x29, #-0xd8]
     2ac:      	add	x1, x19, #0x100
     2b0:      	mov	x0, x22
     2b4:      	stur	q0, [x29, #-0x70]
     2b8:      	ldur	x26, [x29, #-0x68]
     2bc:      	stur	x8, [x29, #-0x60]
     2c0:      	str	x26, [x19, #0x108]
     2c4:      	bl	0x2c4 <_luce_main+0x204>
     2c8:      	cbnz	w0, 0x54c <_luce_main+0x48c>
     2cc:      	add	x1, x19, #0xe8
     2d0:      	add	x2, x19, #0xd0
     2d4:      	mov	x0, x22
     2d8:      	str	x26, [x19, #0xf0]
     2dc:      	bl	0x2dc <_luce_main+0x21c>
     2e0:      	cbnz	w0, 0x554 <_luce_main+0x494>
     2e4:      	ldr	x25, [x19, #0xd8]
     2e8:      	add	x1, x19, #0xb8
     2ec:      	mov	x0, x22
     2f0:      	str	x26, [x19, #0xc0]
     2f4:      	bl	0x2f4 <_luce_main+0x234>
     2f8:      	cbnz	w0, 0x55c <_luce_main+0x49c>
     2fc:      	sub	x1, x29, #0xe8
     300:      	sub	x2, x29, #0x70
     304:      	mov	x0, x22
     308:      	bl	0x308 <_luce_main+0x248>
     30c:      	mov	w8, #0xc                ; =12
     310:      	mov	w9, #0x2                ; =2
     314:      	strb	w8, [x19, #0xa0]
     318:      	stp	x25, x9, [x19, #0xa8]
     31c:      	cbz	x25, 0x498 <_luce_main+0x3d8>
     320:      	ldr	x8, [x25, #0x8]
     324:      	cmp	w8, #0x3
     328:      	b.hs	0x498 <_luce_main+0x3d8>
     32c:      	and	x8, x8, #0x3
     330:      	adrp	x9, 0x0 <ltmp0>
     334:      	add	x9, x9, #0x0
     338:      	ldr	x8, [x9, x8, lsl #3]
     33c:      	sub	x2, x24, #0x1
     340:      	add	x3, x25, #0x18
     344:      	add	x5, x19, #0x78
     348:      	mov	x0, x21
     34c:      	mov	x1, x22
     350:      	mov	w4, #0x2                ; =2
     354:      	blr	x8
     358:      	cbnz	w0, 0x4b0 <_luce_main+0x3f0>
     35c:      	ldr	x8, [x19, #0x78]
     360:      	add	x1, x19, #0x60
     364:      	add	x2, x19, #0x48
     368:      	mov	x0, x22
     36c:      	str	x8, [x19, #0x68]
     370:      	bl	0x370 <_luce_main+0x2b0>
     374:      	cbnz	w0, 0x5b8 <_luce_main+0x4f8>
     378:      	ldp	x9, x10, [x19, #0x50]
     37c:      	ldur	q0, [x19, #0x48]
     380:      	ldr	x8, [x21, #0x8]
     384:      	ldrb	w11, [x19, #0x49]
     388:      	str	q0, [x19, #0x80]
     38c:      	str	x10, [x19, #0x90]
     390:      	cbz	x8, 0x4c0 <_luce_main+0x400>
     394:      	add	x12, x19, #0x48
     398:      	cmp	w11, #0xff
     39c:      	ldr	x0, [x21]
     3a0:      	orr	x12, x12, #0x2
     3a4:      	csel	x2, x10, x11, eq
     3a8:      	csel	x1, x9, x12, eq
     3ac:      	blr	x8
     3b0:      	cmn	w0, #0x1
     3b4:      	b.eq	0x5c8 <_luce_main+0x508>
     3b8:      	cmp	w0, #0x2
     3bc:      	b.hs	0x4c0 <_luce_main+0x400>
     3c0:      	add	x1, x19, #0x80
     3c4:      	add	x2, x19, #0x30
     3c8:      	mov	x0, x22
     3cc:      	bl	0x3cc <_luce_main+0x30c>
     3d0:      	add	x1, x19, #0x18
     3d4:      	mov	x0, x22
     3d8:      	str	x25, [x19, #0x20]
     3dc:      	bl	0x3dc <_luce_main+0x31c>
     3e0:      	cbnz	w0, 0x5d4 <_luce_main+0x514>
     3e4:      	add	x1, x19, #0xa0
     3e8:      	add	x2, x19, #0x0
     3ec:      	mov	x0, x22
     3f0:      	bl	0x3f0 <_luce_main+0x330>
     3f4:      	mov	x0, x22
     3f8:      	mov	x1, x23
     3fc:      	bl	0x3fc <_luce_main+0x33c>
     400:      	mov	w1, wzr
     404:      	mov	x0, x22
     408:      	bl	0x408 <_luce_main+0x348>
     40c:      	mov	w23, w0
     410:      	cmp	w0, #0x2
     414:      	b.eq	0x434 <_luce_main+0x374>
     418:      	ldr	x21, [x21, #0x18]
     41c:      	cbz	x21, 0x434 <_luce_main+0x374>
     420:      	mov	x0, x22
     424:      	bl	0x424 <_luce_main+0x364>
     428:      	mov	x1, x0
     42c:      	mov	x0, x20
     430:      	blr	x21
     434:      	mov	x0, x22
     438:      	bl	0x438 <_luce_main+0x378>
     43c:      	mov	w0, w23
     440:      	sub	sp, x29, #0x50
     444:      	ldp	x29, x30, [sp, #0x50]
     448:      	ldp	x20, x19, [sp, #0x40]
     44c:      	ldp	x22, x21, [sp, #0x30]
     450:      	ldp	x24, x23, [sp, #0x20]
     454:      	ldp	x26, x25, [sp, #0x10]
     458:      	ldp	x28, x27, [sp], #0x60
     45c:      	ret
     460:      	mov	w24, #0x100             ; =256
     464:      	adrp	x0, 0x0 <ltmp0>
     468:      	add	x0, x0, #0x0
     46c:      	mov	w1, #0x3                ; =3
     470:      	bl	0x470 <_luce_main+0x3b0>
     474:      	cbnz	x0, 0x114 <_luce_main+0x54>
     478:      	mov	w23, #0x2               ; =2
     47c:      	b	0x43c <_luce_main+0x37c>
     480:      	adrp	x2, 0x0 <ltmp0>
     484:      	add	x2, x2, #0x0
     488:      	mov	x0, x22
     48c:      	mov	w1, #0xd                ; =13
     490:      	mov	w3, #0x16               ; =22
     494:      	b	0x518 <_luce_main+0x458>
     498:      	adrp	x2, 0x0 <ltmp0>
     49c:      	add	x2, x2, #0x0
     4a0:      	mov	x0, x22
     4a4:      	mov	w1, #0xe                ; =14
     4a8:      	mov	w3, #0x15               ; =21
     4ac:      	bl	0x4ac <_luce_main+0x3ec>
     4b0:      	mov	x0, x22
     4b4:      	mov	w1, #0x1                ; =1
     4b8:      	mov	w2, #0x6                ; =6
     4bc:      	b	0x57c <_luce_main+0x4bc>
     4c0:      	adrp	x2, 0x0 <ltmp0>
     4c4:      	add	x2, x2, #0x0
     4c8:      	mov	x0, x22
     4cc:      	mov	w1, #0x9                ; =9
     4d0:      	mov	w3, #0x18               ; =24
     4d4:      	bl	0x4d4 <_luce_main+0x414>
     4d8:      	mov	x0, x22
     4dc:      	mov	w1, #0x1                ; =1
     4e0:      	mov	w2, #0x9                ; =9
     4e4:      	b	0x57c <_luce_main+0x4bc>
     4e8:      	adrp	x2, 0x0 <ltmp0>
     4ec:      	add	x2, x2, #0x0
     4f0:      	mov	x0, x22
     4f4:      	mov	w1, #0x6                ; =6
     4f8:      	mov	w3, #0x13               ; =19
     4fc:      	bl	0x4fc <_luce_main+0x43c>
     500:      	b	0x58c <_luce_main+0x4cc>
     504:      	adrp	x2, 0x0 <ltmp0>
     508:      	add	x2, x2, #0x0
     50c:      	mov	x0, x22
     510:      	mov	w1, #0xe                ; =14
     514:      	mov	w3, #0x15               ; =21
     518:      	bl	0x518 <_luce_main+0x458>
     51c:      	mov	x0, x22
     520:      	mov	w1, #0x1                ; =1
     524:      	mov	w2, #0x1                ; =1
     528:      	b	0x57c <_luce_main+0x4bc>
     52c:      	adrp	x2, 0x0 <ltmp0>
     530:      	add	x2, x2, #0x0
     534:      	mov	x0, x22
     538:      	mov	w1, #0x6                ; =6
     53c:      	mov	w3, #0x13               ; =19
     540:      	bl	0x540 <_luce_main+0x480>
     544:      	b	0x570 <_luce_main+0x4b0>
     548:      	b	0x560 <_luce_main+0x4a0>
     54c:      	mov	w25, #0x5               ; =5
     550:      	b	0x560 <_luce_main+0x4a0>
     554:      	mov	w25, #0x6               ; =6
     558:      	b	0x560 <_luce_main+0x4a0>
     55c:      	mov	w25, #0x8               ; =8
     560:      	mov	x0, x22
     564:      	mov	w1, wzr
     568:      	mov	w2, w25
     56c:      	bl	0x56c <_luce_main+0x4ac>
     570:      	mov	x0, x22
     574:      	mov	w1, #0x1                ; =1
     578:      	mov	w2, #0x2                ; =2
     57c:      	bl	0x57c <_luce_main+0x4bc>
     580:      	mov	x0, x22
     584:      	mov	x1, x23
     588:      	bl	0x588 <_luce_main+0x4c8>
     58c:      	ldr	x2, [x21, #0x10]
     590:      	mov	x0, x22
     594:      	mov	x1, x20
     598:      	bl	0x598 <_luce_main+0x4d8>
     59c:      	mov	w1, #0x1                ; =1
     5a0:      	mov	x0, x22
     5a4:      	bl	0x5a4 <_luce_main+0x4e4>
     5a8:      	mov	w23, w0
     5ac:      	cmp	w0, #0x2
     5b0:      	b.ne	0x418 <_luce_main+0x358>
     5b4:      	b	0x434 <_luce_main+0x374>
     5b8:      	mov	x0, x22
     5bc:      	mov	w1, #0x1                ; =1
     5c0:      	mov	w2, #0x7                ; =7
     5c4:      	b	0x57c <_luce_main+0x4bc>
     5c8:      	mov	x0, x22
     5cc:      	bl	0x5cc <_luce_main+0x50c>
     5d0:      	b	0x580 <_luce_main+0x4c0>
     5d4:      	mov	x0, x22
     5d8:      	mov	w1, #0x1                ; =1
     5dc:      	mov	w2, #0xe                ; =14
     5e0:      	b	0x57c <_luce_main+0x4bc>

Code and environment

Returned closureThe environment outlives the creating frame
function valuecode pointer + environment handle
closure objectlayout + capture fields + strong count
captured storagevalues, references, cells, weak handles

Four capture meanings

CaptureEnvironment fieldWhat the closure observes
immutable valuevalue copycreation-time snapshot
referenceretained handlesame live identity and mutation
mutable localretained shared cellone variable shared by creator and every closure
[weak name]non-owning generation handleoptional owned upgrade on each read
[copy = expression]result copied or retained onceexplicit creation-time snapshot

Why mutable locals need cells

A stack slot lasts only until the creating function returns. Moving the slot into one ARC cell gives the original scope and every nested closure access to the same mutable value. Each closure retains the cell, so it remains valid after the creator's stack frame ends. The last release destroys the cell and its current value.

Capture planning is semantic

The parser records capture syntax. Semantics resolves each referenced name, checks whether it is a value or supported weak target, detects mutation, builds a stable environment layout, and diagnoses illegal transfers or direct self cycles. MIR only sees the settled layout and operations.

Closure cycles

A class that stores a closure which strongly captures the same class would create a direct cycle: class → closure environment → class. That shape is diagnosed. A weak capture turns the second arrow non-owning and makes the captured name optional inside the body.

Storage and boundaries

Copying a function value retains its environment. Function values can live in locals, fields, optionals, unions, and supported container slots. Their code identity and environment handles belong to one runtime process, so comparison and worker transfer are outside the function-value model.