Luce / engineering
Learn Luce LuciaOS

The native machine-code path

A native build is not one mysterious “compile” step. It is a readable LLVM module, an optimized object file, a platform link, an identity check, and finally a call to luce_main.

Start with the real output

The tabs below contain the same program at the last three code representations. Nothing is marked “schematic.” The LLVM tab is what Luce hands to LLVM. The ARM64 tab is disassembled from the emitted Mach-O object.

Built from this repositoryFollow the same program through four representations
compiler build information

What you wrote. Names and indentation still carry the meaning.

open source

func clamp_double(value: i64, limit: i64) -> i64:
    let doubled = value * 2
    if doubled > limit:
        return limit
    return doubled

func main(args: list[str]):
    print(str(clamp_double(len(args), 10)))

What Luce decided. Types, registers, blocks, calls, and lifetime operations are explicit. This is the IR before LLVM.

open complete MIR

func clamp_double(value: i64, limit: i64) -> i64
    local %2 doubled: i64
  b0:
    r0 = local_get %0
    r1 = const 2
    r2 = multiply.i64 r0, r1
    local_set %2, r2
    r4 = local_get %2
    r5 = local_get %1
    r6 = greater.i64 r4, r5
    branch r6, b1, b2
  b1:
    r8 = local_get %1
    ret r8
  b2:
    r10 = local_get %2
    ret r10
func main(args: list[str]) -> None
    local %1 (temporary): str
  b0:
    r0 = local_get %0
    r1 = intrinsic len, r0
    r2 = const 10
    r3 = call clamp_double, r1, r2
    r4 = intrinsic str_value, r3
    local_set %1, r4
    intrinsic print, r4
    r7 = local_get %1
    r8 = intrinsic drop_storage, r7
    local_set %1, r8
    ret

What the backend handed to LLVM. This is the real textual module before LLVM performs its general optimization and instruction selection.

open complete LLVM IR

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

@luce.text.0 = private unnamed_addr constant [16 x i8] c"integer overflow"
@luce.text.1 = private unnamed_addr constant [0 x i8] zeroinitializer
@luce.text.2 = private unnamed_addr constant [21 x i8] c"null object reference"
@luce.text.3 = private unnamed_addr constant [22 x i8] c"object used after free"
@luce.text.4 = private unnamed_addr constant [19 x i8] c"call depth exceeded"
@luce.text.5 = private unnamed_addr constant [24 x i8] c"host service unavailable"
@luce.text.6 = private unnamed_addr constant [12 x i8] c"clamp_double"
@luce.text.7 = private unnamed_addr constant [58 x i8] c"/Users/sedov/Dev/luciaos/www/lucelang/examples/journey.luc"
@luce.origins.0 = private constant [12 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 3, i32 5 }, { i32, i32 } { i32 3, i32 5 }, { i32, i32 } { i32 3, i32 5 }, { i32, i32 } { i32 3, i32 5 }, { i32, i32 } { i32 4, i32 9 }, { i32, i32 } { i32 4, i32 9 }, { i32, i32 } { i32 5, i32 5 }, { i32, i32 } { i32 5, i32 5 }]
@luce.text.8 = private unnamed_addr constant [4 x i8] c"main"
@luce.origins.1 = private constant [11 x { i32, i32 }] [{ 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.functions = private constant [2 x { ptr, i64, ptr, i64, ptr, i64 }] [{ ptr, i64, ptr, i64, ptr, i64 } { ptr @luce.text.6, i64 12, ptr @luce.text.7, i64 58, ptr @luce.origins.0, i64 12 }, { ptr, i64, ptr, i64, ptr, i64 } { ptr @luce.text.8, i64 4, ptr @luce.text.7, i64 58, ptr @luce.origins.1, i64 11 }]
@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.clamp_double(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
  br label %10

10:
  %11 = load i64, ptr %7, align 8
  %12 = call { i64, i1 } @llvm.smul.with.overflow.i64(i64 %11, i64 2)
  %13 = extractvalue { i64, i1 } %12, 0
  %14 = extractvalue { i64, i1 } %12, 1
  br i1 %14, label %19, label %22, !prof !0

15:
  %16 = load i64, ptr %8, align 8
  store i64 %16, ptr %5, align 8
  ret i32 0

17:
  %18 = load i64, ptr %9, align 8
  store i64 %18, ptr %5, align 8
  ret i32 0

19:
  %20 = extractvalue { ptr, i64 } { ptr @luce.text.0, i64 16 }, 0
  %21 = extractvalue { ptr, i64 } { ptr @luce.text.0, i64 16 }, 1
  call void @luce_rt_raise(ptr %1, i32 0, ptr %20, i64 %21)
  call void @luce_rt_unwound(ptr %1, i32 0, i32 2)
  ret i32 1

22:
  store i64 %13, ptr %9, align 8
  %23 = load i64, ptr %9, align 8
  %24 = load i64, ptr %8, align 8
  %25 = icmp sgt i64 %23, %24
  br i1 %25, label %15, label %17
}

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
  store i64 %3, ptr %5, align 8
  %7 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %6, i32 0, i32 0
  store i8 4, ptr %7, align 1
  %8 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %6, i32 0, i32 1
  store i8 -1, ptr %8, align 1
  %9 = extractvalue { ptr, i64 } { ptr @luce.text.1, i64 0 }, 0
  %10 = ptrtoint ptr %9 to i64
  %11 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %6, i32 0, i32 3
  store i64 %10, ptr %11, align 8
  %12 = extractvalue { ptr, i64 } { ptr @luce.text.1, i64 0 }, 1
  %13 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %6, i32 0, i32 4
  store i64 %12, ptr %13, align 8
  %14 = sub nsw i64 %2, 1
  %15 = alloca i64, align 8
  %16 = alloca { i8, i8, [6 x i8], i64, i64 }, align 8
  %17 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %16, i32 0, i32 0
  store i8 2, ptr %17, align 1
  %18 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %16, i32 0, i32 4
  store i64 0, ptr %18, align 8
  %19 = alloca { i8, i8, [6 x i8], i64, i64 }, align 8
  %20 = alloca { i8, i8, [6 x i8], i64, i64 }, align 8
  br label %21

21:
  %22 = load i64, ptr %5, align 8
  %23 = trunc i64 %22 to i32
  %24 = lshr i64 %22, 32
  %25 = trunc i64 %24 to i32
  %26 = icmp eq i32 %23, -1
  br i1 %26, label %27, label %30, !prof !0

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

30:
  %31 = getelementptr inbounds i8, ptr %1, i64 96
  %32 = load ptr, ptr %31, align 8!alias.scope !1, !noalias !2
  %33 = zext i32 %23 to i64
  %34 = mul nsw i64 %33, 112
  %35 = getelementptr inbounds i8, ptr %32, i64 %34
  %36 = getelementptr inbounds i8, ptr %35, i64 96
  %37 = load i32, ptr %36, align 4, !alias.scope !1, !noalias !2
  %38 = icmp ne i32 %37, %25
  br i1 %38, label %39, label %42, !prof !0

39:
  %40 = extractvalue { ptr, i64 } { ptr @luce.text.3, i64 22 }, 0
  %41 = extractvalue { ptr, i64 } { ptr @luce.text.3, i64 22 }, 1
  call void @luce_rt_raise(ptr %1, i32 13, ptr %40, i64 %41)
  call void @luce_rt_unwound(ptr %1, i32 1, i32 1)
  ret i32 1

42:
  %43 = and i32 %37, 1
  %44 = icmp ne i32 %43, 0
  br i1 %44, label %45, label %48, !prof !0

45:
  %46 = extractvalue { ptr, i64 } { ptr @luce.text.3, i64 22 }, 0
  %47 = extractvalue { ptr, i64 } { ptr @luce.text.3, i64 22 }, 1
  call void @luce_rt_raise(ptr %1, i32 13, ptr %46, i64 %47)
  call void @luce_rt_unwound(ptr %1, i32 1, i32 1)
  ret i32 1

48:
  %49 = getelementptr inbounds i8, ptr %35, i64 16
  %50 = load i64, ptr %49, align 8!alias.scope !1, !noalias !2
  %51 = load ptr, ptr %35, align 8, !alias.scope !1, !noalias !2
  %52 = icmp slt i64 %14, 1
  br i1 %52, label %53, label %56, !prof !0

53:
  %54 = extractvalue { ptr, i64 } { ptr @luce.text.4, i64 19 }, 0
  %55 = extractvalue { ptr, i64 } { ptr @luce.text.4, i64 19 }, 1
  call void @luce_rt_raise(ptr %1, i32 6, ptr %54, i64 %55)
  call void @luce_rt_unwound(ptr %1, i32 1, i32 3)
  ret i32 1

56:
  %57 = call i32 @luce.0.clamp_double(ptr %0, ptr %1, i64 %14, i64 %50, i64 10, ptr %15)
  %58 = icmp ne i32 %57, 0
  br i1 %58, label %59, label %60, !prof !0

59:
  call void @luce_rt_unwound(ptr %1, i32 1, i32 3)
  ret i32 1

60:
  %61 = load i64, ptr %15, align 8
  %62 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %16, i32 0, i32 3
  store i64 %61, ptr %62, align 8
  %63 = call i32 @luce_rt_str(ptr %1, ptr %16, ptr %19)
  %64 = icmp ne i32 %63, 0
  br i1 %64, label %65, label %66, !prof !0

65:
  call void @luce_rt_unwound(ptr %1, i32 1, i32 4)
  ret i32 1

66:
  %67 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %19, i32 0, i32 3
  %68 = load i64, ptr %67, align 8
  %69 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %19, i32 0, i32 1
  %70 = load i8, ptr %69, align 1
  %71 = icmp eq i8 %70, -1
  %72 = inttoptr i64 %68 to ptr
  %73 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %19, i32 0, i32 2
  %74 = select i1 %71, ptr %72, ptr %73
  %75 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %19, i32 0, i32 4
  %76 = load i64, ptr %75, align 8
  %77 = zext i8 %70 to i64
  %78 = select i1 %71, i64 %76, i64 %77
  %79 = insertvalue { ptr, i64 } poison, ptr %74, 0
  %80 = insertvalue { ptr, i64 } %79, i64 %78, 1
  call void @llvm.memcpy.inline.p0.p0.i64(ptr align 8 %6, ptr align 8 %19, i64 24, i1 false)
  %81 = extractvalue { ptr, i64 } %80, 0
  %82 = extractvalue { ptr, i64 } %80, 1
  %83 = 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
  %84 = load ptr, ptr %83, align 8
  %85 = icmp eq ptr %84, null
  br i1 %85, label %86, label %89, !prof !0

86:
  %87 = extractvalue { ptr, i64 } { ptr @luce.text.5, i64 24 }, 0
  %88 = extractvalue { ptr, i64 } { ptr @luce.text.5, i64 24 }, 1
  call void @luce_rt_raise(ptr %1, i32 9, ptr %87, i64 %88)
  call void @luce_rt_unwound(ptr %1, i32 1, i32 6)
  ret i32 1

89:
  %90 = 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
  %91 = load ptr, ptr %90, align 8
  %92 = call i32 %84(ptr %91, ptr %81, i64 %82)
  %93 = icmp eq i32 %92, -1
  br i1 %93, label %94, label %95, !prof !0

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

95:
  %96 = icmp ne i32 %92, 0
  %97 = icmp ne i32 %92, 1
  %98 = and i1 %96, %97
  br i1 %98, label %99, label %102, !prof !0

99:
  %100 = extractvalue { ptr, i64 } { ptr @luce.text.5, i64 24 }, 0
  %101 = extractvalue { ptr, i64 } { ptr @luce.text.5, i64 24 }, 1
  call void @luce_rt_raise(ptr %1, i32 9, ptr %100, i64 %101)
  call void @luce_rt_unwound(ptr %1, i32 1, i32 6)
  ret i32 1

102:
  %103 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %6, i32 0, i32 3
  %104 = load i64, ptr %103, align 8
  %105 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %6, i32 0, i32 1
  %106 = load i8, ptr %105, align 1
  %107 = icmp eq i8 %106, -1
  %108 = inttoptr i64 %104 to ptr
  %109 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %6, i32 0, i32 2
  %110 = select i1 %107, ptr %108, ptr %109
  %111 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %6, i32 0, i32 4
  %112 = load i64, ptr %111, align 8
  %113 = zext i8 %106 to i64
  %114 = select i1 %107, i64 %112, i64 %113
  %115 = insertvalue { ptr, i64 } poison, ptr %110, 0
  %116 = insertvalue { ptr, i64 } %115, i64 %114, 1
  call void @luce_rt_drop_storage(ptr %1, ptr %6, ptr %20)
  %117 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %20, i32 0, i32 3
  %118 = load i64, ptr %117, align 8
  %119 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %20, i32 0, i32 1
  %120 = load i8, ptr %119, align 1
  %121 = icmp eq i8 %120, -1
  %122 = inttoptr i64 %118 to ptr
  %123 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %20, i32 0, i32 2
  %124 = select i1 %121, ptr %122, ptr %123
  %125 = getelementptr inbounds { i8, i8, [6 x i8], i64, i64 }, ptr %20, i32 0, i32 4
  %126 = load i64, ptr %125, align 8
  %127 = zext i8 %120 to i64
  %128 = select i1 %121, i64 %126, i64 %127
  %129 = insertvalue { ptr, i64 } poison, ptr %124, 0
  %130 = insertvalue { ptr, i64 } %129, i64 %128, 1
  call void @llvm.memcpy.inline.p0.p0.i64(ptr align 8 %6, ptr align 8 %20, i64 24, i1 false)
  ret i32 0
}

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

; 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 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 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) #2

; 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) #3

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

; 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) #5

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 2)
  %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.4, 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) #6

; 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) #7

; 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) #8

; 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) #7

; 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) #9

; 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) #9

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

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

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

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

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

attributes #0 = { nounwind speculatable willreturn nofree nosync nocallback memory(none) }
attributes #1 = { nounwind cold willreturn memory(argmem: readwrite, inaccessiblemem: readwrite) }
attributes #2 = { nounwind willreturn memory(read, argmem: readwrite, inaccessiblemem: readwrite) }
attributes #3 = { nounwind willreturn nofree nocallback memory(argmem: readwrite) }
attributes #4 = { nounwind cold willreturn memory(argmem: write) }
attributes #5 = { nounwind willreturn memory(argmem: readwrite, inaccessiblemem: readwrite) }
attributes #6 = { nounwind willreturn memory(argmem: read, inaccessiblemem: readwrite) }
attributes #7 = { nounwind willreturn memory(argmem: readwrite) }
attributes #8 = { nounwind willreturn memory(readwrite) }
attributes #9 = { nounwind memory(readwrite) }
attributes #10 = { cold }
attributes #11 = { 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"}

What reached the object file. The platform disassembler shows the optimized ARM64 instructions, including inlining and trap branches.

open complete assembly


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

Disassembly of section __TEXT,__text:

0000000000000000 <ltmp0>:
; luce_main():
       0:      	stp	x24, x23, [sp, #-0x40]!
       4:      	stp	x22, x21, [sp, #0x10]
       8:      	stp	x20, x19, [sp, #0x20]
       c:      	stp	x29, x30, [sp, #0x30]
      10:      	add	x29, sp, #0x30
      14:      	sub	sp, sp, #0x70
      18:      	ldr	x8, [x0, #0x70]
      1c:      	ldr	x19, [x0]
      20:      	mov	x20, x0
      24:      	cbz	x8, 0x50 <ltmp0+0x50>
      28:      	mov	x0, x19
      2c:      	blr	x8
      30:      	mov	x23, x0
      34:      	adrp	x0, 0x0 <ltmp0>
      38:      	add	x0, x0, #0x0
      3c:      	mov	w1, #0x2                ; =2
      40:      	mov	w22, #0x2               ; =2
      44:      	bl	0x44 <ltmp0+0x44>
      48:      	cbnz	x0, 0x6c <ltmp0+0x6c>
      4c:      	b	0x21c <ltmp0+0x21c>
      50:      	mov	w23, #0x100             ; =256
      54:      	adrp	x0, 0x0 <ltmp0>
      58:      	add	x0, x0, #0x0
      5c:      	mov	w1, #0x2                ; =2
      60:      	mov	w22, #0x2               ; =2
      64:      	bl	0x64 <ltmp0+0x64>
      68:      	cbz	x0, 0x21c <ltmp0+0x21c>
      6c:      	ldp	x3, x4, [x20, #0x1b0]
      70:      	mov	x21, x0
      74:      	ldp	x5, x6, [x20, #0x1c0]
      78:      	ldr	x2, [x20, #0xe0]
      7c:      	ldp	x8, x9, [x20, #0xf8]
      80:      	ldr	x7, [x20, #0x1d0]
      84:      	ldur	q0, [x20, #0xe8]
      88:      	sub	sp, sp, #0x20
      8c:      	mov	x1, x19
      90:      	stp	x8, x9, [sp, #0x10]
      94:      	str	q0, [sp]
      98:      	bl	0x98 <ltmp0+0x98>
      9c:      	add	sp, sp, #0x20
      a0:      	ldp	x2, x3, [x20, #0x180]
      a4:      	mov	x0, x21
      a8:      	ldp	x4, x5, [x20, #0x190]
      ac:      	mov	x1, x19
      b0:      	ldr	x6, [x20, #0x1a0]
      b4:      	bl	0xb4 <ltmp0+0xb4>
      b8:      	ldp	x8, x9, [x20, #0x170]
      bc:      	ldp	x2, x3, [x20, #0x140]
      c0:      	ldp	x4, x5, [x20, #0x150]
      c4:      	ldp	x6, x7, [x20, #0x160]
      c8:      	stp	x8, x9, [sp, #-0x10]!
      cc:      	mov	x0, x21
      d0:      	mov	x1, x19
      d4:      	bl	0xd4 <ltmp0+0xd4>
      d8:      	add	sp, sp, #0x10
      dc:      	cmp	x23, #0x0
      e0:      	b.le	0x278 <ltmp0+0x278>
      e4:      	sub	x22, sp, #0x20
      e8:      	mov	sp, x22
      ec:      	ldp	x2, x3, [x20, #0x20]
      f0:      	mov	x0, x21
      f4:      	mov	x1, x19
      f8:      	mov	x4, x22
      fc:      	bl	0xfc <ltmp0+0xfc>
     100:      	cbnz	w0, 0x32c <ltmp0+0x32c>
     104:      	ldr	x8, [x22, #0x8]
     108:      	mov	w9, #0x2                ; =2
     10c:      	stur	xzr, [x29, #-0x58]
     110:      	sturb	w9, [x29, #-0x68]
     114:      	cmn	w8, #0x1
     118:      	b.eq	0x294 <ltmp0+0x294>
     11c:      	mov	w9, #0x70               ; =112
     120:      	ldr	x10, [x21, #0x60]
     124:      	umaddl	x9, w8, w9, x10
     128:      	lsr	x8, x8, #32
     12c:      	ldr	w10, [x9, #0x60]
     130:      	cmp	w10, w8
     134:      	b.ne	0x238 <ltmp0+0x238>
     138:      	tbnz	w8, #0x0, 0x238 <ltmp0+0x238>
     13c:      	cmp	x23, #0x1
     140:      	b.eq	0x2bc <ltmp0+0x2bc>
     144:      	ldr	x8, [x9, #0x10]
     148:      	mov	x9, #0x4000000000000000 ; =4611686018427387904
     14c:      	cmn	x8, x9
     150:      	b.mi	0x2d8 <ltmp0+0x2d8>
     154:      	lsl	x8, x8, #1
     158:      	mov	w9, #0xa                ; =10
     15c:      	sub	x1, x29, #0x68
     160:      	sub	x2, x29, #0x80
     164:      	mov	x0, x21
     168:      	cmp	x8, #0xa
     16c:      	csel	x8, x8, x9, lt
     170:      	stur	x8, [x29, #-0x60]
     174:      	bl	0x174 <ltmp0+0x174>
     178:      	cbnz	w0, 0x310 <ltmp0+0x310>
     17c:      	ldp	x9, x10, [x29, #-0x78]
     180:      	ldur	q0, [x29, #-0x80]
     184:      	ldr	x8, [x20, #0x8]
     188:      	ldurb	w11, [x29, #-0x7f]
     18c:      	stur	q0, [x29, #-0x50]
     190:      	stur	x10, [x29, #-0x40]
     194:      	cbz	x8, 0x250 <ltmp0+0x250>
     198:      	sub	x12, x29, #0x80
     19c:      	cmp	w11, #0xff
     1a0:      	ldr	x0, [x20]
     1a4:      	orr	x12, x12, #0x2
     1a8:      	csel	x2, x10, x11, eq
     1ac:      	csel	x1, x9, x12, eq
     1b0:      	blr	x8
     1b4:      	cmn	w0, #0x1
     1b8:      	b.eq	0x358 <ltmp0+0x358>
     1bc:      	cmp	w0, #0x2
     1c0:      	b.hs	0x250 <ltmp0+0x250>
     1c4:      	sub	x1, x29, #0x50
     1c8:      	sub	x2, x29, #0x98
     1cc:      	mov	x0, x21
     1d0:      	bl	0x1d0 <ltmp0+0x1d0>
     1d4:      	mov	x0, x21
     1d8:      	mov	x1, x22
     1dc:      	bl	0x1dc <ltmp0+0x1dc>
     1e0:      	mov	w1, wzr
     1e4:      	mov	x0, x21
     1e8:      	bl	0x1e8 <ltmp0+0x1e8>
     1ec:      	mov	w22, w0
     1f0:      	cmp	w0, #0x2
     1f4:      	b.eq	0x214 <ltmp0+0x214>
     1f8:      	ldr	x20, [x20, #0x18]
     1fc:      	cbz	x20, 0x214 <ltmp0+0x214>
     200:      	mov	x0, x21
     204:      	bl	0x204 <ltmp0+0x204>
     208:      	mov	x1, x0
     20c:      	mov	x0, x19
     210:      	blr	x20
     214:      	mov	x0, x21
     218:      	bl	0x218 <ltmp0+0x218>
     21c:      	mov	w0, w22
     220:      	sub	sp, x29, #0x30
     224:      	ldp	x29, x30, [sp, #0x30]
     228:      	ldp	x20, x19, [sp, #0x20]
     22c:      	ldp	x22, x21, [sp, #0x10]
     230:      	ldp	x24, x23, [sp], #0x40
     234:      	ret
     238:      	adrp	x2, 0x0 <ltmp0>
     23c:      	add	x2, x2, #0x0
     240:      	mov	x0, x21
     244:      	mov	w1, #0xd                ; =13
     248:      	mov	w3, #0x16               ; =22
     24c:      	b	0x2a8 <ltmp0+0x2a8>
     250:      	adrp	x2, 0x0 <ltmp0>
     254:      	add	x2, x2, #0x0
     258:      	mov	x0, x21
     25c:      	mov	w1, #0x9                ; =9
     260:      	mov	w3, #0x18               ; =24
     264:      	bl	0x264 <ltmp0+0x264>
     268:      	mov	x0, x21
     26c:      	mov	w1, #0x1                ; =1
     270:      	mov	w2, #0x6                ; =6
     274:      	b	0x31c <ltmp0+0x31c>
     278:      	adrp	x2, 0x0 <ltmp0>
     27c:      	add	x2, x2, #0x0
     280:      	mov	x0, x21
     284:      	mov	w1, #0x6                ; =6
     288:      	mov	w3, #0x13               ; =19
     28c:      	bl	0x28c <ltmp0+0x28c>
     290:      	b	0x32c <ltmp0+0x32c>
     294:      	adrp	x2, 0x0 <ltmp0>
     298:      	add	x2, x2, #0x0
     29c:      	mov	x0, x21
     2a0:      	mov	w1, #0xe                ; =14
     2a4:      	mov	w3, #0x15               ; =21
     2a8:      	bl	0x2a8 <ltmp0+0x2a8>
     2ac:      	mov	x0, x21
     2b0:      	mov	w1, #0x1                ; =1
     2b4:      	mov	w2, #0x1                ; =1
     2b8:      	b	0x31c <ltmp0+0x31c>
     2bc:      	adrp	x2, 0x0 <ltmp0>
     2c0:      	add	x2, x2, #0x0
     2c4:      	mov	x0, x21
     2c8:      	mov	w1, #0x6                ; =6
     2cc:      	mov	w3, #0x13               ; =19
     2d0:      	bl	0x2d0 <ltmp0+0x2d0>
     2d4:      	b	0x300 <ltmp0+0x300>
     2d8:      	adrp	x2, 0x0 <ltmp0>
     2dc:      	add	x2, x2, #0x0
     2e0:      	mov	x0, x21
     2e4:      	mov	w1, wzr
     2e8:      	mov	w3, #0x10               ; =16
     2ec:      	bl	0x2ec <ltmp0+0x2ec>
     2f0:      	mov	x0, x21
     2f4:      	mov	w1, wzr
     2f8:      	mov	w2, #0x2                ; =2
     2fc:      	bl	0x2fc <ltmp0+0x2fc>
     300:      	mov	x0, x21
     304:      	mov	w1, #0x1                ; =1
     308:      	mov	w2, #0x3                ; =3
     30c:      	b	0x31c <ltmp0+0x31c>
     310:      	mov	x0, x21
     314:      	mov	w1, #0x1                ; =1
     318:      	mov	w2, #0x4                ; =4
     31c:      	bl	0x31c <ltmp0+0x31c>
     320:      	mov	x0, x21
     324:      	mov	x1, x22
     328:      	bl	0x328 <ltmp0+0x328>
     32c:      	ldr	x2, [x20, #0x10]
     330:      	mov	x0, x21
     334:      	mov	x1, x19
     338:      	bl	0x338 <ltmp0+0x338>
     33c:      	mov	w1, #0x1                ; =1
     340:      	mov	x0, x21
     344:      	bl	0x344 <ltmp0+0x344>
     348:      	mov	w22, w0
     34c:      	cmp	w0, #0x2
     350:      	b.ne	0x1f8 <ltmp0+0x1f8>
     354:      	b	0x214 <ltmp0+0x214>
     358:      	mov	x0, x21
     35c:      	bl	0x35c <ltmp0+0x35c>
     360:      	b	0x320 <ltmp0+0x320>

What LLVM changed

Luce’s LLVM IR keeps clamp_double as an internal function with a checked-multiply intrinsic, a comparison, and two returns. The optimized object has no separate symbol for that helper. LLVM inlined it into luce_main, proved that a left shift is a valid multiplication by two after the overflow check, and used a conditional select for the cap.

LLVM IR

llvm.smul.with.overflow.i64
icmp sgt
br to two return blocks

ARM64 object

cmn + b.mi
lsl #1
cmp + csel

The two columns do not look alike, but they make the same promises: overflow traps, and the returned integer is the doubled value unless it exceeds the limit.

What the object still does not know

An object file contains native instructions and data, but some addresses are unresolved. A call to the runtime may still say, in effect, “the linker will tell me where this symbol lives.” Relocation records name those places.

The last build stepsNative all the way through
program.oinstructions, symbols, relocations, artifact tag
platform linkerjoins runtime and resolves addresses
program or .lcloadable native container
artifact checkmachine, ABI, generator, source
OS loadermaps pages and applies dynamic relocations
luce_main(host)native entry with explicit capabilities

Why the platform driver performs the link

The compiler invokes the platform C driver because it already knows the system startup objects, SDK paths, thread and math libraries, architecture flags, and loader conventions. A standalone executable adds libluce_start.a; a .lc becomes a loadable library; both link libluce_rt.a.

This happens at build time. A finished program does not carry LLVM and does not invoke a compiler when it starts.

What luce_main does

  1. Check the host.Terminal errors and traps need a reporting path.
  2. Install runtime capabilities.Resources and workers need explicit callbacks for cleanup and host work.
  3. Create program roots.Constant containers become objects owned by this run.
  4. Call the generated main.Arguments, call depth, errors, and source traces use the internal ABI visible in LLVM IR.
  5. Finish distinctly.Success, an uncaught error, a trap, exhaustion, and explicit exit remain different results.

How to read the assembly tab

The object is optimized, so source functions may be inlined and local names are gone. Start by searching for operations you expect: lsl for doubling, cmp for the cap, and blr or bl for runtime calls. Branches leading away from the happy path often implement Luce’s stale-handle, overflow, bounds, call-depth, or host-service checks.

Addresses such as 0x174 are object-local. The linker will relocate calls and data references. Registers and offsets may also change with LLVM version, optimization mode, or target, while Luce’s observable behavior stays the same.

Why the runner stays small

loom does not link LLVM. On a cache miss it gives serialized MIR to the sibling luce compiler. On a hit it checks the native artifact, asks the operating system to load it, finds luce_main, and calls it. A machine that only runs already-built Luce programs needs no LLVM installation.