(x < y ? 1 : 0) is precisely the borrow-out from x - y, or bit 64 if you view them as arbitrarily zero-extended bignums. There's a bunch of ways to get at that bit, but probably the easiest to understand is to just split each of x and y into high and low halves, subtract low halves, shift the borrow down, subtract high halves with the borrow, and shift the borrow down to get 1 or 0 out.
(1) If you’re hoping to get constant-time code, know that this is more likely to result in constant-time code, but it is not guaranteed to result in constant-time code, because LLVM can and will optimize bitwise operations to conditions. (Note that the code you get from an optimized x < y ? 1 : 0 will almost certainly be constant-time on any modern CPU, post-optimization.)
I found a bug in my "standard library free" implementation of "func <" used in a side project. The code in question looks like:
static func < (a: XUInt64, b: XUInt64) -> XBool {
let c = a - b
if case .i = c.tuple.elements.7.bits.elements.7 {
return .true
}
return .false
}
As written it doesn't handle overflows correctly, and the listed "allowed" primitive operations is about all I have available at my disposal.
OTOH, I could just use a loop and scan through the bit string from the most significant to the least significant bits and find the first difference. Will give that a try as well.
It'd be nice if it were in the standard library like it is in Rust. It's not problematic like it is in C, because you have to call the initializer explicitly.