diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp index 90baa054eed4c..311064eebf99d 100644 --- a/llvm/lib/Analysis/InstructionSimplify.cpp +++ b/llvm/lib/Analysis/InstructionSimplify.cpp @@ -2557,6 +2557,14 @@ static Value *simplifyXorInst(Value *Op0, Value *Op1, const SimplifyQuery &Q, return X; } + // (xor (or disjoint X, Y), Y) -> X + { + Value *X; + if (match(Op0, m_c_DisjointOr(m_Value(X), m_Specific(Op1))) || + match(Op1, m_c_DisjointOr(m_Value(X), m_Specific(Op0)))) + return X; + } + return nullptr; } diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp index c6f317a668cfe..e87e31e162c29 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -5866,6 +5866,24 @@ static void collectOffsetOp(Value *V, SmallVectorImpl &Offsets, Offsets.emplace_back(Instruction::Xor, Inst->getOperand(1)); Offsets.emplace_back(Instruction::Xor, Inst->getOperand(0)); break; + case Instruction::Or: + if (cast(Inst)->isDisjoint()) + Offsets.emplace_back(Instruction::Xor, Inst->getOperand(1)); + Offsets.emplace_back(Instruction::Xor, Inst->getOperand(0)); + break; + case Instruction::Shl: + if (auto *OBO = cast(Inst)) { + if (OBO->hasNoSignedWrap()) + Offsets.emplace_back(Instruction::AShr, Inst->getOperand(1)); + else if (OBO->hasNoUnsignedWrap()) + Offsets.emplace_back(Instruction::LShr, Inst->getOperand(1)); + } + break; + case Instruction::AShr: + case Instruction::LShr: + if (auto *PEO = cast(Inst); PEO && PEO->isExact()) + Offsets.emplace_back(Instruction::Shl, Inst->getOperand(1)); + break; case Instruction::Select: if (AllowRecursion) { collectOffsetOp(Inst->getOperand(1), Offsets, /*AllowRecursion=*/false); diff --git a/llvm/test/Transforms/InstCombine/icmp-select.ll b/llvm/test/Transforms/InstCombine/icmp-select.ll index a038731abbc48..2a4009d24fcf2 100644 --- a/llvm/test/Transforms/InstCombine/icmp-select.ll +++ b/llvm/test/Transforms/InstCombine/icmp-select.ll @@ -836,3 +836,63 @@ define i1 @discr_eq_constantexpr(ptr %p) { %cmp = icmp eq i64 %sub, -1 ret i1 %cmp } + +define i1 @or_disjoint_eq(i8 %a, i1 %cond) { +; CHECK-LABEL: @or_disjoint_eq( +; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[COND:%.*]], i8 8, i8 4 +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[A:%.*]], [[TMP1]] +; CHECK-NEXT: ret i1 [[CMP]] +; + %or = or disjoint i8 %a, 3 + %sel = select i1 %cond, i8 11, i8 7 + %cmp = icmp eq i8 %or, %sel + ret i1 %cmp +} + +define i1 @shl_nsw_eq(i8 %a, i1 %cond) { +; CHECK-LABEL: @shl_nsw_eq( +; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[COND:%.*]], i8 1, i8 2 +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[A:%.*]], [[TMP1]] +; CHECK-NEXT: ret i1 [[CMP]] +; + %a_shl = shl nsw i8 %a, 3 + %sel = select i1 %cond, i8 8, i8 16 + %cmp = icmp eq i8 %a_shl, %sel + ret i1 %cmp +} + +define i1 @shl_nuw_eq(i8 %a, i1 %cond) { +; CHECK-LABEL: @shl_nuw_eq( +; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[COND:%.*]], i8 1, i8 4 +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[A:%.*]], [[TMP1]] +; CHECK-NEXT: ret i1 [[CMP]] +; + %a_shl = shl nuw i8 %a, 3 + %sel = select i1 %cond, i8 8, i8 32 + %cmp = icmp eq i8 %a_shl, %sel + ret i1 %cmp +} + +define i1 @ashr_exact_eq(i8 %a, i1 %cond) { +; CHECK-LABEL: @ashr_exact_eq( +; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[COND:%.*]], i8 48, i8 16 +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[A:%.*]], [[TMP1]] +; CHECK-NEXT: ret i1 [[CMP]] +; + %a_shl = ashr exact i8 %a, 2 + %sel = select i1 %cond, i8 12, i8 4 + %cmp = icmp eq i8 %a_shl, %sel + ret i1 %cmp +} + +define i1 @lshr_exact_eq(i8 %a, i1 %cond) { +; CHECK-LABEL: @lshr_exact_eq( +; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[COND:%.*]], i8 48, i8 16 +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[A:%.*]], [[TMP1]] +; CHECK-NEXT: ret i1 [[CMP]] +; + %a_shl = lshr exact i8 %a, 2 + %sel = select i1 %cond, i8 12, i8 4 + %cmp = icmp eq i8 %a_shl, %sel + ret i1 %cmp +} diff --git a/llvm/test/Transforms/InstSimplify/xor.ll b/llvm/test/Transforms/InstSimplify/xor.ll index eaa016b6614e1..c7b0766bb65c4 100644 --- a/llvm/test/Transforms/InstSimplify/xor.ll +++ b/llvm/test/Transforms/InstSimplify/xor.ll @@ -301,3 +301,21 @@ define <2 x i4> @xor_or_and_not_poison_elt(<2 x i4> %a, <2 x i4> %b) { %r = xor <2 x i4> %or, %and ret <2 x i4> %r } + +define i8 @xor_or_disjoint(i8 %a, i8 %b) { +; CHECK-LABEL: @xor_or_disjoint( +; CHECK-NEXT: ret i8 [[B:%.*]] +; + %or = or disjoint i8 %a, %b + %xor = xor i8 %or, %a + ret i8 %xor +} + +define i8 @xor_or_disjoint_c(i8 %a, i8 %b) { +; CHECK-LABEL: @xor_or_disjoint_c( +; CHECK-NEXT: ret i8 [[B:%.*]] +; + %or = or disjoint i8 %b, %a + %xor = xor i8 %a, %or + ret i8 %xor +}