Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Base.issubnormal(::BFloat16) is missing #86

Open
dzhang314 opened this issue Nov 1, 2024 · 6 comments
Open

Base.issubnormal(::BFloat16) is missing #86

dzhang314 opened this issue Nov 1, 2024 · 6 comments

Comments

@dzhang314
Copy link

dzhang314 commented Nov 1, 2024

The floating-point introspection function issubnormal(x) is not implemented for x::BFloat16. Since BFloat16 has the same exponent range as Float32, I suggest the following implementation:

@inline Base.issubnormal(x::BFloat16) = issubnormal(Float32(x))

This compiles to nice, clean assembly, at least on arm:

	.build_version macos, 15, 0
	.globl	_julia_issubnormal_42           ; -- Begin function julia_issubnormal_42
	.p2align	2
_julia_issubnormal_42:                  ; @julia_issubnormal_42
; %bb.0:                                ; %top
	tst	w0, #0x7f80
	cset	w8, eq
	tst	w0, #0x7f
	cset	w9, ne
	and	w0, w8, w9
	ret
                                        ; -- End function
.subsections_via_symbols
@milankl
Copy link
Member

milankl commented Nov 1, 2024

Could we not just check that the exponent bits are all zero? i.e. Base.exponent_mask(BFloat16) & reinterpret(UInt16, x) == 0?

@dzhang314
Copy link
Author

dzhang314 commented Nov 1, 2024

@milankl No; recall that zero has encoding 0x0000 or 0x8000 but is not considered subnormal. But I think you're right that iszero(Base.exponent_mask(BFloat16) & reinterpret(UInt16, x)) & ~iszero(x) is a correct implementation, and I think that is effectively what the generated assembly for issubnormal(Float32(x)) is doing.

@milankl
Copy link
Member

milankl commented Nov 1, 2024

Riiight my bad! But now I see what you mean by "clean", the conversion to Float32 (that I wanted to avoid) is indeed compiled away. Bit surprised to see that, but yes I would naively check for exponent = 0 and mantissa > 0. Not sure whether relying on the compiler translating to that is the best strategy though given we already know what we actually want to do in bitwise operations? Sure what you suggest is short but much less literal?

@milankl
Copy link
Member

milankl commented Nov 1, 2024

Actually you write ~iszero(x) but this line tst w0, #0x7f is Base.significand_mask(BFloat16) & ui no?

@dzhang314
Copy link
Author

That's fair! I was also surprised to see the compiler could entirely reason away the conversion to Float32, and I also prefer not to rely too much on compiler optimization where it can be easily avoided. And you're right, exponent = 0 and mantissa != 0 is exactly what the generated assembly is checking for.

@dzhang314
Copy link
Author

As another data point, this also generates good assembly on x86-64.

	.text
	.file	"issubnormal"
	.globl	julia_issubnormal_787           # -- Begin function julia_issubnormal_787
	.p2align	4, 0x90
	.type	julia_issubnormal_787,@function
julia_issubnormal_787:                  # @julia_issubnormal_787
# %bb.0:                                # %top
	push	rbp
	mov	rbp, rsp
	test	edi, 32640
	sete	cl
	test	dil, 127
	setne	al
	and	al, cl
	pop	rbp
	ret
.Lfunc_end0:
	.size	julia_issubnormal_787, .Lfunc_end0-julia_issubnormal_787
                                        # -- End function
	.section	".note.GNU-stack","",@progbits

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants