A->getType()->isIntOrIntVectorTy(1))
return SelectInst::Create(A, Op0, Constant::getNullValue(Ty));
+ // Similarly, a 'not' of the bool translates to a swap of the select arms:
+ // ~sext(A) & Op1 --> A ? 0 : Op1
+ // Op0 & ~sext(A) --> A ? 0 : Op0
+ if (match(Op0, m_Not(m_SExt(m_Value(A)))) &&
+ A->getType()->isIntOrIntVectorTy(1))
+ return SelectInst::Create(A, Constant::getNullValue(Ty), Op1);
+ if (match(Op1, m_Not(m_SExt(m_Value(A)))) &&
+ A->getType()->isIntOrIntVectorTy(1))
+ return SelectInst::Create(A, Constant::getNullValue(Ty), Op0);
+
// (iN X s>> (N-1)) & Y --> (X s< 0) ? Y : 0 -- with optional sext
if (match(&I, m_c_And(m_OneUse(m_SExtOrSelf(
m_AShr(m_Value(X), m_APIntAllowUndef(C)))),
; CHECK-LABEL: @and_not_sext_to_sel(
; CHECK-NEXT: [[SEXT:%.*]] = sext <2 x i1> [[Y:%.*]] to <2 x i32>
; CHECK-NEXT: call void @use_vec(<2 x i32> [[SEXT]])
-; CHECK-NEXT: [[NOT:%.*]] = xor <2 x i32> [[SEXT]], <i32 -1, i32 -1>
-; CHECK-NEXT: [[R:%.*]] = and <2 x i32> [[NOT]], [[X:%.*]]
+; CHECK-NEXT: [[R:%.*]] = select <2 x i1> [[Y]], <2 x i32> zeroinitializer, <2 x i32> [[X:%.*]]
; CHECK-NEXT: ret <2 x i32> [[R]]
;
%sext = sext <2 x i1> %y to <2 x i32>
; CHECK-NEXT: call void @use(i32 [[SEXT]])
; CHECK-NEXT: [[NOT:%.*]] = xor i32 [[SEXT]], -1
; CHECK-NEXT: call void @use(i32 [[NOT]])
-; CHECK-NEXT: [[R:%.*]] = and i32 [[X]], [[NOT]]
+; CHECK-NEXT: [[R:%.*]] = select i1 [[Y]], i32 0, i32 [[X]]
; CHECK-NEXT: ret i32 [[R]]
;
%x = mul i32 %px, %px ; thwart complexity-based canonicalization
ret i32 %r
}
+; negative test - must be 'not'
+
define i32 @and_xor_sext_to_sel(i32 %x, i1 %y) {
; CHECK-LABEL: @and_xor_sext_to_sel(
; CHECK-NEXT: [[SEXT:%.*]] = sext i1 [[Y:%.*]] to i32
ret i32 %r
}
+; negative test - must be 'sext'
+
define i32 @and_not_zext_to_sel(i32 %x, i1 %y) {
; CHECK-LABEL: @and_not_zext_to_sel(
; CHECK-NEXT: [[ZEXT:%.*]] = zext i1 [[Y:%.*]] to i32