we don't currently infer that ~( ~(a|b) | (a&b) ) -> a^b and similar, e.g. ~(~a & ~b) & ~(a&b) -> a^b
Compile this with llvm-gcc: unsigned int *a, *b; void joy(void) { a[20] = ~(~(a[10]|b[10]) | (a[10]&b[10])); } and you get: define void @joy() { entry: %tmp = load i32** @a ; <i32*> [#uses=2] %tmp2 = getelementptr i32* %tmp, i32 10 ; <i32*> [#uses=1] %tmp3 = load i32* %tmp2 ; <i32> [#uses=2] %tmp4 = load i32** @b ; <i32*> [#uses=1] %tmp5 = getelementptr i32* %tmp4, i32 10 ; <i32*> [#uses=1] %tmp6 = load i32* %tmp5 ; <i32> [#uses=2] %tmp7 = or i32 %tmp6, %tmp3 ; <i32> [#uses=1] %tmp7not = xor i32 %tmp7, -1 ; <i32> [#uses=1] %tmp14 = and i32 %tmp6, %tmp3 ; <i32> [#uses=1] %tmp15 = or i32 %tmp14, %tmp7not ; <i32> [#uses=1] %tmp15not = xor i32 %tmp15, -1 ; <i32> [#uses=1] %tmp16 = getelementptr i32* %tmp, i32 20 ; <i32*> [#uses=1] store i32 %tmp15not, i32* %tmp16 ret void } it could just use xor?
Created attachment 1011 [details] this module is really just doing an xor
Here's a C vector example: typedef unsigned __attribute__((vector_size(16))) vu; vu test1(vu a, vu b) { return ~(~(a|b) | (a&b)); } vu test2(vu a, vu b) { return (a|b) & ~(a&b); }
Implemented. There are many patches to this, the primary ones being: http://lists.cs.uiuc.edu/pipermail/llvm-commits/Week-of-Mon-20070611/050487.html http://lists.cs.uiuc.edu/pipermail/llvm-commits/Week-of-Mon-20070611/050489.html http://lists.cs.uiuc.edu/pipermail/llvm-commits/Week-of-Mon-20070611/050495.html Testcase here: Transforms/InstCombine/and-or-not.ll This shrunk Duraid's nasty example from 32K lines of x86-64 .s file to 23k lines. -Chris