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

[x86] Failure to remove all statements in function that doesn't return anything but should #46760

Closed
GabrielRavier opened this issue Sep 4, 2020 · 8 comments
Labels
bugzilla Issues migrated from bugzilla

Comments

@GabrielRavier
Copy link
Contributor

Bugzilla Link 47416
Resolution FIXED
Resolved on Sep 07, 2020 08:12
Version trunk
OS Linux
CC @topperc,@jdoerfert,@RKSimon,@rotateright
Fixed by commit(s) b22910d

Extended Description

int f(int a, int b)
{
if ((a < 4 && b == 'r') || (a == 1 && (b == 'h' || b == 'i')) || (a == 2))
a = b;
}

Compiling this results in this assembly output:

f(int, int):
cmp edi, 1

It should be possible to remove the cmp edi, 1 as far as I know. I guess this isn't really by itself considering the behaviour is undefined anyway but this behaviour itself seems rather weird.

@GabrielRavier
Copy link
Contributor Author

It also seems to completely fail to realise that the code has to be unreachable (unless UB occurs). If I add this code (with f still visible) :

int g(bool cond, int a, int b)
{
if (cond)
return f(a, b);
return 12;
}

LLVM is incapable of optimizing this to return 12; (removing the conditional), instead inlining the broken f and jumping to it if cond is true. If I change the body of f to nothing, it manages to do so properly (and the codegen for f emits nothing as expected).

@GabrielRavier
Copy link
Contributor Author

PS: In my second comment, I am not saying that behaviour should be defined where cond == true. I am saying that the code is not properly optimized based on the fact that f cannot be called without invoking UB.

@GabrielRavier
Copy link
Contributor Author

Also, here is a Godbolt comparison with GCC (which is capable of optimizing this better than LLVM) : https://godbolt.org/z/Kbs1f1

@GabrielRavier
Copy link
Contributor Author

Extra note: This doesn't occur when compiling the code as C (https://godbolt.org/z/n5d65h), so this bug seems even odder now.

@rotateright
Copy link
Contributor

@rotateright
Copy link
Contributor

Changing to IR bug - the sooner we can remove dead code, the better (potentially, there's also some clang front-end part of this to account for the C/C++ difference).

@jdoerfert
Copy link
Member

To echo here what was aid in a review [0], we should have a pass early on removing all instructions preceding an unreachable if the are known to transfer control.

For the example https://godbolt.org/z/Kbs1f1 , the Attributor knows f is noreturn and replaces the return in g with unreachable. That results in the "good" code: https://godbolt.org/z/6j36x8

That said, we might want to have a more localized optimization doing this, and finally land the default willreturn and nounwind annotations for intrinsics.

[0] https://reviews.llvm.org/D87149#2256885

@rotateright
Copy link
Contributor

Should be fixed with more instcombine zapping:
https://reviews.llvm.org/rGb22910daab95

Depending on target, we may do better than nothing on UB code as shown in the description. For example, on x86, I see a 'ud2' instruction, so that should crash and make the programmer aware of their buggy code even if they ignore the compile-time warning:
47416.cpp:5:1: warning: non-void function does not return a value [-Wreturn-type]

@llvmbot llvmbot transferred this issue from llvm/llvm-bugzilla-archive Dec 10, 2021
This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bugzilla Issues migrated from bugzilla
Projects
None yet
Development

No branches or pull requests

3 participants