Not sure if this is a bug, or I’m missing something about understanding the output of @code_lowered and Cthulhu’s @descend. The following REPL snippet shows a very simple function, which if called with argument nothing does nothing. @code_llvm shows that the compiler can infer this as I would expect (having a function body that is just ret void), but @code_lowered marks lines as ‘dynamic’ and Cthulhu marks the line as ‘runtime’ (which gets red-highlighted in the REPL) - both of these look like worrying warnings that I would think I should fix to get good performance, but it seems to me like these are false positives. Am I missing something?
_
_ _ _(_)_ | Documentation: https://docs.julialang.org
(_) | (_) (_) |
_ _ _| |_ __ _ | Type "?" for help, "]?" for Pkg help.
| | | | | | |/ _` | |
| | |_| | | | (_| | | Version 1.12.1 (2025-10-17)
_/ |\__'_|_|_|\__'_| | Official https://julialang.org release
|__/ |
julia> using Cthulhu
julia> function foo(x)
if x !== nothing
println("hello")
end
end
foo (generic function with 1 method)
julia> @code_llvm foo(nothing)
; Function Signature: foo(Nothing)
; @ REPL[2]:1 within `foo`
define void @julia_foo_3953() #0 {
top:
; @ REPL[2] within `foo`
ret void
}
julia> @code_lowered foo(nothing)
CodeInfo(
1 ─ %1 = Main.:!==
│ %2 = Main.nothing
│ %3 = dynamic (%1)(x, %2)
└── goto #3 if not %3
2 ─ %5 = Main.println
│ %6 = dynamic (%5)("hello")
└── return %6
3 ─ return nothing
)
julia> @descend foo(nothing)
foo(x) @ Main REPL[2]:1
1 function foo(x::Core.Const(nothing))::Core.Const(nothing)
2 if (x::Core.Const(nothing) !== nothing::Core.Const(nothing))::Core.Const(false)
3 println("hello")
4 end
5 end
Select a call to descend into or ↩ to ascend. [q]uit. [b]ookmark.
Toggles: [w]arn, [h]ide type-stable statements, [t]ype annotations, [s]yntax highlight for Source/LLVM/Native, [j]ump to source always.
Show: [S]ource code, [A]ST, [T]yped code, [L]LVM IR, [N]ative code
Actions: [E]dit source code, [R]evise and redisplay
• runtime x::Core.Const(nothing) !== nothing::Core.Const(nothing)
↩
Note that if I’d used === instead of !==, I would get the results I expect with Cthulhu (no ‘runtime’ annotations), which I why I think this is a bug related to !==. @code_lowered still says ‘dynamic’ on a couple of lines though
julia> using Cthulhu
julia> function bar(x)
if x === nothing
println("hello")
end
end
bar (generic function with 1 method)
julia> @code_lowered bar(1)
CodeInfo(
1 ─ %1 = Main.:(===)
│ %2 = Main.nothing
│ %3 = dynamic (%1)(x, %2)
└── goto #3 if not %3
2 ─ %5 = Main.println
│ %6 = dynamic (%5)("hello")
└── return %6
3 ─ return nothing
)
julia> @code_lowered bar(nothing)
CodeInfo(
1 ─ %1 = Main.:(===)
│ %2 = Main.nothing
│ %3 = dynamic (%1)(x, %2)
└── goto #3 if not %3
2 ─ %5 = Main.println
│ %6 = dynamic (%5)("hello")
└── return %6
3 ─ return nothing
)
julia> @descend bar(nothing)
bar(x) @ Main REPL[2]:1
1 function bar(x::Core.Const(nothing))::Core.Const(nothing)
2 if (x::Core.Const(nothing) === nothing::Core.Const(nothing))::Core.Const(true)
3 println("hello")
4 end
5 end
Select a call to descend into or ↩ to ascend. [q]uit. [b]ookmark.
Toggles: [w]arn, [h]ide type-stable statements, [t]ype annotations, [s]yntax highlight for Source/LLVM/Native, [j]ump to source always.
Show: [S]ource code, [A]ST, [T]yped code, [L]LVM IR, [N]ative code
Actions: [E]dit source code, [R]evise and redisplay
• %6 = println(::String)::Core.Const(nothing)
↩
@xal it’s true that @code_typed shows the results I’d expect. My main issue is that Cthulhu.@descend gives misleading (?) information - in a more complicated code, @descend is much easier to use than @code_typed!
Thanks @Benny - I can ignore the ‘dynamic’ then. So the only question left is why Cthulhu is inconsistent between !== and ===, with the !== output looking wrong.