llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
28.99k stars 11.95k forks source link

-Wdouble-promotion warning falsely emitted when floating point literals are not actually promoted to doubles #50620

Open llvmbot opened 3 years ago

llvmbot commented 3 years ago
Bugzilla Link 51276
Version 11.0
OS All
Reporter LLVM Bugzilla Contributor
CC @dwblaikie,@DougGregor,@gburgessiv,@zygoloid

Extended Description

Clang emits a double promotion warning when using the literal 0.5 with a float and optimization turned on.

For example:

float func(float num) { return num * 0.5; }

warning: implicit conversion increases floating-point precision: 'float' to 'double' [-Wdouble-promotion] return num * 0.5;

However, if optimization is turned on (-Os, -O1 and above), Clang does not actually use the double representation for this literal (and others than can be represented equally in float as in double). The assembler output for both "0.5" and "0.5f" is the same:

.LCPI0_0: .long 1056964608 # float 0.5 func(float): # @​func(float) mulss xmm0, dword ptr [rip + .LCPI0_0] ret

One of the most relevant scopes for -Wdouble-promotion is probably optimization (in particular for SIMD), where the unintended use of a double would cause a significant performance hit. If the compiler is smart enough and is not using doubles and double instructions, and no precision is changed anywhere in the process, it should be smart enough to not throw a this warning.

llvmbot commented 3 years ago

Woah, blast from the past...

I don't really have any skin in this game, but from a "strict correctness" side of things, I'm going to side on the side of keeping the warning.

That code includes a double promotion by the spec. If you don't want that, you should be explicit about it, regardless of whether a specific optimization level happens to cause different internal behaviour.

dwblaikie commented 3 years ago

Might just agree to disagree here, though I've cc'd a few folks who were involved in implementing the warning in clang originally - perhaps they've got some ideas.

llvmbot commented 3 years ago

It's a fairly intentional architectural/design choice not to use optimizations for warnings because doing so makes warnings unreliable/

In my view, in this case, the warning is already unreliable. The compiler warns about something that it optimizes away safely without a negative effect. The issue it warns about does not occur. It's a false alert.

volatile to optimizations which is generally undesirable.

I don't share this view. I would like to be informed by the compiler about real problems in the very specific compiling. For problems due to the language standard that do might occur with other compiler options instead, I'd be happy to use -Wpedantic or something similar.

The warning here is about how the language is implemented, not any particular optimizations that happen later.

Then the warning is at least misleading, and I think it should be pointed out in the warning that the compiler may not actually do a double promotion if the 32 least significant bits are zero. This check could be done in the warning code.

The fix would be to change the floating point literal 0.5 to 0.5f, which avoids the conversions.

This would be a fix in which the user would need to analyze if in a particular floating point number, the 32 least significant bits are zero. This task seems much better left exclusively to the compiler, in my opinion.

But there are scenarios where this seems not a desirable approach. For example a template function. The literal 3.1415f is different from 3.1415.

Likewise if one would suggest to use static_cast(0.5), one could argue, that the problem is exactly the same as it would still be an optimization if the compiler chooses to compute the cast at compile time rather than at runtime.

Of course, static_cast(0.5) always bloats the code - unnecessarily in this case.

dwblaikie commented 3 years ago

Anyway, in this case, if the warning machinery has no clue what the code generation/optimization machinery does, would it make sense and be possible to move the double promotion and conversion warnings into the code generation/optimization machinery? Since Clangs does have optimization reports, I'm anticipating that there is a messaging infrastructure in this part of Clang/LLVM that could be used for this?

It's a fairly intentional architectural/design choice not to use optimizations for warnings because doing so makes warnings unreliable/volatile to optimizations which is generally undesirable. There is the remarks infrastructure, but it's intended to be distinct/clearly separate from warnings. (& there are one or two warnings that are implemented down in LLVM for practical reasons - like warning about the size of a stack frame, which just has to be down there)

The warning here is about how the language is implemented, not any particular optimizations that happen later. The fix would be to change the floating point literal 0.5 to 0.5f, which avoids the conversions.

llvmbot commented 3 years ago

Perhaps another option could be turning the floating point literal conversion optimization on in all optimization levels including -O0.

Then, the warning machinery could safely assume that if all 32 least significant bits in a double precision literal are zero, the literal is not promoted to a double if only used with floats.

llvmbot commented 3 years ago

Thanks for pointing that out. Perhaps, then, there should be warnings about compiler warnings that they may not reflect what the compiler actually does? :)

Anyway, in this case, if the warning machinery has no clue what the code generation/optimization machinery does, would it make sense and be possible to move the double promotion and conversion warnings into the code generation/optimization machinery? Since Clangs does have optimization reports, I'm anticipating that there is a messaging infrastructure in this part of Clang/LLVM that could be used for this?

dwblaikie commented 3 years ago

FWIW: Generally Clang's warnings have no connection to the code generation/optimizations that LLVM makes, so if you're hoping to improve the quality of a warning by making it depend on optimization choices - that's probably not a viable path forward in the Clang project.