Index: llvm/trunk/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp =================================================================== --- llvm/trunk/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ llvm/trunk/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -2351,6 +2351,30 @@ } } + // Instead of trying to imitate the folds for and/or, decompose this 'xor' + // into those logic ops. That is, try to turn this into an and-of-icmps + // because we have many folds for that pattern. + // + // This is based on a truth table definition of xor: + // X ^ Y --> (X | Y) & !(X & Y) + if (Value *OrICmp = SimplifyBinOp(Instruction::Or, LHS, RHS, SQ)) { + // TODO: If OrICmp is true, then the definition of xor simplifies to !(X&Y). + // TODO: If OrICmp is false, the whole thing is false (InstSimplify?). + if (Value *AndICmp = SimplifyBinOp(Instruction::And, LHS, RHS, SQ)) { + // TODO: Independently handle cases where the 'and' side is a constant. + if (OrICmp == LHS && AndICmp == RHS && RHS->hasOneUse()) { + // (LHS | RHS) & !(LHS & RHS) --> LHS & !RHS + RHS->setPredicate(RHS->getInversePredicate()); + return Builder->CreateAnd(LHS, RHS); + } + if (OrICmp == RHS && AndICmp == LHS && LHS->hasOneUse()) { + // !(LHS & RHS) & (LHS | RHS) --> !LHS & !RHS + LHS->setPredicate(LHS->getInversePredicate()); + return Builder->CreateAnd(LHS, RHS); + } + } + } + return nullptr; } Index: llvm/trunk/test/Transforms/InstCombine/set.ll =================================================================== --- llvm/trunk/test/Transforms/InstCombine/set.ll +++ llvm/trunk/test/Transforms/InstCombine/set.ll @@ -164,10 +164,8 @@ define i1 @xor_of_icmps(i64 %a) { ; CHECK-LABEL: @xor_of_icmps( -; CHECK-NEXT: [[B:%.*]] = icmp sgt i64 %a, 0 -; CHECK-NEXT: [[C:%.*]] = icmp eq i64 %a, 1 -; CHECK-NEXT: [[XOR:%.*]] = xor i1 [[C]], [[B]] -; CHECK-NEXT: ret i1 [[XOR]] +; CHECK-NEXT: [[TMP1:%.*]] = icmp sgt i64 %a, 1 +; CHECK-NEXT: ret i1 [[TMP1]] ; %b = icmp sgt i64 %a, 0 %c = icmp eq i64 %a, 1 @@ -179,10 +177,8 @@ define i1 @xor_of_icmps_commute(i64 %a) { ; CHECK-LABEL: @xor_of_icmps_commute( -; CHECK-NEXT: [[B:%.*]] = icmp sgt i64 %a, 0 -; CHECK-NEXT: [[C:%.*]] = icmp eq i64 %a, 1 -; CHECK-NEXT: [[XOR:%.*]] = xor i1 [[B]], [[C]] -; CHECK-NEXT: ret i1 [[XOR]] +; CHECK-NEXT: [[TMP1:%.*]] = icmp sgt i64 %a, 1 +; CHECK-NEXT: ret i1 [[TMP1]] ; %b = icmp sgt i64 %a, 0 %c = icmp eq i64 %a, 1 @@ -209,10 +205,10 @@ define i32 @PR2844(i32 %x) { ; CHECK-LABEL: @PR2844( -; CHECK-NEXT: [[A:%.*]] = icmp eq i32 %x, 0 +; CHECK-NEXT: [[A:%.*]] = icmp ne i32 %x, 0 ; CHECK-NEXT: [[B:%.*]] = icmp sgt i32 %x, -638208502 -; CHECK-NEXT: [[NOT_OR:%.*]] = xor i1 [[A]], [[B]] -; CHECK-NEXT: [[SEL:%.*]] = zext i1 [[NOT_OR]] to i32 +; CHECK-NEXT: [[TMP1:%.*]] = and i1 [[A]], [[B]] +; CHECK-NEXT: [[SEL:%.*]] = zext i1 [[TMP1]] to i32 ; CHECK-NEXT: ret i32 [[SEL]] ; %A = icmp eq i32 %x, 0