What is `slt_int`

What is Core.Intrinsics.slt_int? As seen in base/sort.jl, added 2013.

Also, how can I find out the answer to this sort of question in general? I tried @edit, ?, web searches, and even git blame (a much less ideal solution), but none came up with anything.

Emperically:

using Test

values = Float64[
    0.0, -0.0, 1.0, -1.0, pi, 1/pi, Inf, -Inf, NaN, -NaN, 
    rand(), 1/rand(), -rand(), -1/rand(), 
    reinterpret(Float64, reinterpret(UInt64, NaN) | 78782),
    -reinterpret(Float64, reinterpret(UInt64, NaN) | 78782)]

@testset "slt_int == isless(reinterpret(Int, ⋅))" begin
    for a in values
        for b in values
            @test Core.Intrinsics.slt_int(a, b) == 
                  isless(reinterpret(Int64, a), reinterpret(Int64, b))
        end
    end
end
Test Summary:                          | Pass  Total
slt_int == isless(reinterpret(Int, ⋅)) |  256    256
2 Likes

It is an intrinsic that implements signed less than for integers. That particular line is a bit tricky since it applies integer intrinsics directly to floating-point values. Normally, I’d express that by reinterpreting to an integer type with the same size and then doing the normal isless comparison, but this tricky way to do it leverages the fact that intrinsics generate the right sized instructions based on the storage size of the arguments they get. That test you referenced verifies that slt_int has the same effect as that reinterpretation and isless comparison for floating-point values.

Intrinsics are an internal language implementation detail, not part of the official surface API, so they’re not documented. Code generation for slt_int is defined in this line:

https://github.com/JuliaLang/julia/blob/628209c1f2f746e3fc21ccd7cb34e67289403d44/src/intrinsics.cpp#L1339

You can see that it calls the LLVM method, CreateICmpSLT, which is documented here the meanings of which are documented here.

6 Likes

Thanks! It’s nice to know for sure what is going on.

1 Like

Is there any reason we define

struct Right <: Ordering end
right(::DirectOrdering) = Right()
lt(::Right, x::T, y::T) where {T<:Floats} = slt_int(x, y)

In https://github.com/JuliaLang/julia/blob/b2d15f05698ba78ac2493ec2624a0ee1c9a042a3/base/sort.jl#L1123
instead of

right(::DirectOrdering) = Reverse(Left())

?

Not sure, I didn’t write that code.

You didn’t?
https://github.com/JuliaLang/julia/commit/69b21e1c1c210e91ef3ebb278ea8946df90111e1

That code is 9 years old, I think it’s fine to not quite remember why it was written this exact way :slight_smile: If it wasn’t specially documented, there probably was not a specific reason (though that’s a very fuzzy indicator, so if it there was a reason and it can be documented now, that’d be good too - and even more amazing if future additions have a nice comment/git log trail).

2 Likes

That doesn’t include anything called Right so I can’t speak to why that is the way it is.

@Sukera is right, and the way it’s written isn’t posing a problem, so I’m happy to move on. This is the history, though:

Rename from FpRev to Rev
https://github.com/JuliaLang/julia/commit/25919dc9913f6d370776413625e1b2a342fcdccc#diff-7af133c263575ae298b5b0747b2ee9593e87eef99222ed17bfe458520a75e709L276

Rename from Rev to Right
https://github.com/JuliaLang/julia/commit/17c619b214791bc3401b9171366b848bd45c3e9c

In digging through the history, I answered my own question. When Right was originally written, Reverse wasn’t parametric. You only added that here
https://github.com/JuliaLang/julia/commit/3326e0ce5b87d0162d9594f404526f55e33b8094

And nobody got around to using Reverse in the Sort.Float module. This raises the question: should we change it now? I could make a PR if appropriate.