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.
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 fileMIR 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 fileLLVM 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
i1operand 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 tomainfrom 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 fileARM64 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
x30and 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
Four capture meanings
| Capture | Environment field | What the closure observes |
|---|---|---|
| immutable value | value copy | creation-time snapshot |
| reference | retained handle | same live identity and mutation |
| mutable local | retained shared cell | one variable shared by creator and every closure |
[weak name] | non-owning generation handle | optional owned upgrade on each read |
[copy = expression] | result copied or retained once | explicit 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.