diff --git a/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp index 4d653e5d611..5c0caa1cbfd 100644 --- a/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ b/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -1641,24 +1641,55 @@ Instruction *InstCombiner::MatchBSwap(BinaryOperator &I) { /// We have an expression of the form (A&C)|(B&D). Check if A is (cond?-1:0) /// and either B or D is ~(cond?-1,0) or (cond?0,-1), then we can simplify this /// expression to "cond ? C : D or B". -static Instruction *matchSelectFromAndOr(Value *A, Value *B, - Value *C, Value *D) { +static Instruction *matchSelectFromAndOr(Value *A, Value *B, Value *C, Value *D, + InstCombiner::BuilderTy &Builder) { // If A is not a select of -1/0, this cannot match. Value *Cond = nullptr; - if (!match(A, m_SExt(m_Value(Cond))) || !Cond->getType()->isIntegerTy(1)) - return nullptr; + if (match(A, m_SExt(m_Value(Cond))) && + Cond->getType()->getScalarType()->isIntegerTy(1)) { - // ((cond?-1:0)&C) | (B&(cond?0:-1)) -> cond ? C : B. - if (match(D, m_Not(m_SExt(m_Specific(Cond))))) - return SelectInst::Create(Cond, C, B); - if (match(D, m_SExt(m_Not(m_Specific(Cond))))) - return SelectInst::Create(Cond, C, B); + // ((cond ? -1:0) & C) | (B & (cond ? 0:-1)) -> cond ? C : B. + if (match(D, m_Not(m_SExt(m_Specific(Cond))))) + return SelectInst::Create(Cond, C, B); + if (match(D, m_SExt(m_Not(m_Specific(Cond))))) + return SelectInst::Create(Cond, C, B); - // ((cond?-1:0)&C) | ((cond?0:-1)&D) -> cond ? C : D. - if (match(B, m_Not(m_SExt(m_Specific(Cond))))) - return SelectInst::Create(Cond, C, D); - if (match(B, m_SExt(m_Not(m_Specific(Cond))))) - return SelectInst::Create(Cond, C, D); + // ((cond ? -1:0) & C) | ((cond ? 0:-1) & D) -> cond ? C : D. + if (match(B, m_Not(m_SExt(m_Specific(Cond))))) + return SelectInst::Create(Cond, C, D); + if (match(B, m_SExt(m_Not(m_Specific(Cond))))) + return SelectInst::Create(Cond, C, D); + } + + // TODO: Refactor the pattern matching above and below so there's less code. + + // The sign-extended boolean condition may be hiding behind a bitcast. In that + // case, look for the same patterns as above. However, we need to bitcast the + // input operands to the select and bitcast the output of the select to match + // the expected types. + if (match(A, m_BitCast(m_SExt(m_Value(Cond)))) && + Cond->getType()->getScalarType()->isIntegerTy(1)) { + + Type *SrcType = cast(A)->getSrcTy(); + + // ((bc Cond) & C) | (B & (bc ~Cond)) --> bc (select Cond, (bc C), (bc B)) + if (match(D, m_CombineOr(m_BitCast(m_Not(m_SExt(m_Specific(Cond)))), + m_BitCast(m_SExt(m_Not(m_Specific(Cond))))))) { + Value *BitcastC = Builder.CreateBitCast(C, SrcType); + Value *BitcastB = Builder.CreateBitCast(B, SrcType); + Value *Select = Builder.CreateSelect(Cond, BitcastC, BitcastB); + return CastInst::Create(Instruction::BitCast, Select, A->getType()); + } + + // ((bc Cond) & C) | ((bc ~Cond) & D) --> bc (select Cond, (bc C), (bc D)) + if (match(B, m_CombineOr(m_BitCast(m_Not(m_SExt(m_Specific(Cond)))), + m_BitCast(m_SExt(m_Not(m_Specific(Cond))))))) { + Value *BitcastC = Builder.CreateBitCast(C, SrcType); + Value *BitcastD = Builder.CreateBitCast(D, SrcType); + Value *Select = Builder.CreateSelect(Cond, BitcastC, BitcastD); + return CastInst::Create(Instruction::BitCast, Select, A->getType()); + } + } return nullptr; } @@ -2256,13 +2287,13 @@ Instruction *InstCombiner::visitOr(BinaryOperator &I) { } // (A & (C0?-1:0)) | (B & ~(C0?-1:0)) -> C0 ? A : B, and commuted variants. - if (Instruction *Match = matchSelectFromAndOr(A, B, C, D)) + if (Instruction *Match = matchSelectFromAndOr(A, B, C, D, *Builder)) return Match; - if (Instruction *Match = matchSelectFromAndOr(B, A, D, C)) + if (Instruction *Match = matchSelectFromAndOr(B, A, D, C, *Builder)) return Match; - if (Instruction *Match = matchSelectFromAndOr(C, B, A, D)) + if (Instruction *Match = matchSelectFromAndOr(C, B, A, D, *Builder)) return Match; - if (Instruction *Match = matchSelectFromAndOr(D, A, B, C)) + if (Instruction *Match = matchSelectFromAndOr(D, A, B, C, *Builder)) return Match; // ((A&~B)|(~A&B)) -> A^B diff --git a/test/Transforms/InstCombine/logical-select.ll b/test/Transforms/InstCombine/logical-select.ll index d2648c2a57b..a6b17b39c96 100644 --- a/test/Transforms/InstCombine/logical-select.ll +++ b/test/Transforms/InstCombine/logical-select.ll @@ -77,19 +77,16 @@ define i32 @par(i32 %a, i32 %b, i32 %c, i32 %d) { ret i32 %t3 } -; FIXME: In the following tests, verify that a bitcast doesn't get in the way +; In the following tests, verify that a bitcast doesn't get in the way ; of a select transform. These bitcasts are common in SSE/AVX and possibly ; other vector code because of canonicalization to i64 elements for vectors. define <2 x i64> @bitcast_select(<4 x i1> %cmp, <2 x i64> %a, <2 x i64> %b) { ; CHECK-LABEL: @bitcast_select( -; CHECK-NEXT: [[SEXT:%.*]] = sext <4 x i1> %cmp to <4 x i32> -; CHECK-NEXT: [[T2:%.*]] = bitcast <4 x i32> [[SEXT]] to <2 x i64> -; CHECK-NEXT: [[AND:%.*]] = and <2 x i64> [[T2]], %a -; CHECK-NEXT: [[NEG:%.*]] = xor <4 x i32> [[SEXT]], -; CHECK-NEXT: [[NEG2:%.*]] = bitcast <4 x i32> [[NEG]] to <2 x i64> -; CHECK-NEXT: [[AND2:%.*]] = and <2 x i64> [[NEG2]], %b -; CHECK-NEXT: [[OR:%.*]] = or <2 x i64> [[AND]], [[AND2]] +; CHECK-NEXT: [[TMP1:%.*]] = bitcast <2 x i64> %a to <4 x i32> +; CHECK-NEXT: [[TMP2:%.*]] = bitcast <2 x i64> %b to <4 x i32> +; CHECK-NEXT: [[TMP3:%.*]] = select <4 x i1> %cmp, <4 x i32> [[TMP1]], <4 x i32> [[TMP2]] +; CHECK-NEXT: [[OR:%.*]] = bitcast <4 x i32> [[TMP3]] to <2 x i64> ; CHECK-NEXT: ret <2 x i64> [[OR]] ; %sext = sext <4 x i1> %cmp to <4 x i32> @@ -104,13 +101,10 @@ define <2 x i64> @bitcast_select(<4 x i1> %cmp, <2 x i64> %a, <2 x i64> %b) { define <2 x i64> @bitcast_select_swap_or_ops(<4 x i1> %cmp, <2 x i64> %a, <2 x i64> %b) { ; CHECK-LABEL: @bitcast_select_swap_or_ops( -; CHECK-NEXT: [[SEXT:%.*]] = sext <4 x i1> %cmp to <4 x i32> -; CHECK-NEXT: [[T2:%.*]] = bitcast <4 x i32> [[SEXT]] to <2 x i64> -; CHECK-NEXT: [[AND:%.*]] = and <2 x i64> [[T2]], %a -; CHECK-NEXT: [[NEG:%.*]] = xor <4 x i32> [[SEXT]], -; CHECK-NEXT: [[NEG2:%.*]] = bitcast <4 x i32> [[NEG]] to <2 x i64> -; CHECK-NEXT: [[AND2:%.*]] = and <2 x i64> [[NEG2]], %b -; CHECK-NEXT: [[OR:%.*]] = or <2 x i64> [[AND2]], [[AND]] +; CHECK-NEXT: [[TMP1:%.*]] = bitcast <2 x i64> %a to <4 x i32> +; CHECK-NEXT: [[TMP2:%.*]] = bitcast <2 x i64> %b to <4 x i32> +; CHECK-NEXT: [[TMP3:%.*]] = select <4 x i1> %cmp, <4 x i32> [[TMP1]], <4 x i32> [[TMP2]] +; CHECK-NEXT: [[OR:%.*]] = bitcast <4 x i32> [[TMP3]] to <2 x i64> ; CHECK-NEXT: ret <2 x i64> [[OR]] ; %sext = sext <4 x i1> %cmp to <4 x i32> @@ -125,13 +119,10 @@ define <2 x i64> @bitcast_select_swap_or_ops(<4 x i1> %cmp, <2 x i64> %a, <2 x i define <2 x i64> @bitcast_select_swap_and_ops(<4 x i1> %cmp, <2 x i64> %a, <2 x i64> %b) { ; CHECK-LABEL: @bitcast_select_swap_and_ops( -; CHECK-NEXT: [[SEXT:%.*]] = sext <4 x i1> %cmp to <4 x i32> -; CHECK-NEXT: [[T2:%.*]] = bitcast <4 x i32> [[SEXT]] to <2 x i64> -; CHECK-NEXT: [[AND:%.*]] = and <2 x i64> [[T2]], %a -; CHECK-NEXT: [[NEG:%.*]] = xor <4 x i32> [[SEXT]], -; CHECK-NEXT: [[NEG2:%.*]] = bitcast <4 x i32> [[NEG]] to <2 x i64> -; CHECK-NEXT: [[AND2:%.*]] = and <2 x i64> [[NEG2]], %b -; CHECK-NEXT: [[OR:%.*]] = or <2 x i64> [[AND]], [[AND2]] +; CHECK-NEXT: [[TMP1:%.*]] = bitcast <2 x i64> %a to <4 x i32> +; CHECK-NEXT: [[TMP2:%.*]] = bitcast <2 x i64> %b to <4 x i32> +; CHECK-NEXT: [[TMP3:%.*]] = select <4 x i1> %cmp, <4 x i32> [[TMP1]], <4 x i32> [[TMP2]] +; CHECK-NEXT: [[OR:%.*]] = bitcast <4 x i32> [[TMP3]] to <2 x i64> ; CHECK-NEXT: ret <2 x i64> [[OR]] ; %sext = sext <4 x i1> %cmp to <4 x i32> @@ -146,13 +137,10 @@ define <2 x i64> @bitcast_select_swap_and_ops(<4 x i1> %cmp, <2 x i64> %a, <2 x define <2 x i64> @bitcast_select_swap_and_ops2(<4 x i1> %cmp, <2 x i64> %a, <2 x i64> %b) { ; CHECK-LABEL: @bitcast_select_swap_and_ops2( -; CHECK-NEXT: [[SEXT:%.*]] = sext <4 x i1> %cmp to <4 x i32> -; CHECK-NEXT: [[T2:%.*]] = bitcast <4 x i32> [[SEXT]] to <2 x i64> -; CHECK-NEXT: [[AND:%.*]] = and <2 x i64> [[T2]], %a -; CHECK-NEXT: [[NEG:%.*]] = xor <4 x i32> [[SEXT]], -; CHECK-NEXT: [[NEG2:%.*]] = bitcast <4 x i32> [[NEG]] to <2 x i64> -; CHECK-NEXT: [[AND2:%.*]] = and <2 x i64> [[NEG2]], %b -; CHECK-NEXT: [[OR:%.*]] = or <2 x i64> [[AND]], [[AND2]] +; CHECK-NEXT: [[TMP1:%.*]] = bitcast <2 x i64> %a to <4 x i32> +; CHECK-NEXT: [[TMP2:%.*]] = bitcast <2 x i64> %b to <4 x i32> +; CHECK-NEXT: [[TMP3:%.*]] = select <4 x i1> %cmp, <4 x i32> [[TMP1]], <4 x i32> [[TMP2]] +; CHECK-NEXT: [[OR:%.*]] = bitcast <4 x i32> [[TMP3]] to <2 x i64> ; CHECK-NEXT: ret <2 x i64> [[OR]] ; %sext = sext <4 x i1> %cmp to <4 x i32>