Test case: long f(long align) { return (align - 1) & -align; } long g(long align) { return (align - 1) & ~(align - 1); } int h(long align) { return -align == ~(align - 1); } Generated assembly: f: leaq -1(%rdi), %rax negq %rdi andq %rdi, %rax retq g: xorl %eax, %eax retq h: movl $1, %eax retq
This is a special-case of a more general pattern that ends in a bitwise logic op and includes add/sub operands. For example: https://alive2.llvm.org/ce/z/mxoxUz I think these are the generalizations we should handle in instsimplify: https://rise4fun.com/Alive/gR0
https://reviews.llvm.org/rG38ca7face67e