diff --git a/llvm/test/Transforms/InstCombine/add-mask-neg.ll b/llvm/test/Transforms/InstCombine/add-mask-neg.ll new file mode 100644 index 0000000000000..7a7d4216e3bd7 --- /dev/null +++ b/llvm/test/Transforms/InstCombine/add-mask-neg.ll @@ -0,0 +1,121 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -S -passes=instcombine | FileCheck %s + +; +; TODO: Canonicalize ((X & -X) - 1) --> (~X & (X - 1)) +; + +define i32 @dec_mask_neg_i32(i32 %X) { +; CHECK-LABEL: @dec_mask_neg_i32( +; CHECK-NEXT: [[NEG:%.*]] = sub i32 0, [[X:%.*]] +; CHECK-NEXT: [[MASK:%.*]] = and i32 [[NEG]], [[X]] +; CHECK-NEXT: [[DEC:%.*]] = add i32 [[MASK]], -1 +; CHECK-NEXT: ret i32 [[DEC]] +; + %neg = sub i32 0, %X + %mask = and i32 %neg, %X + %dec = add i32 %mask, -1 + ret i32 %dec +} + +define i32 @dec_mask_commute_neg_i32(i32 %X) { +; CHECK-LABEL: @dec_mask_commute_neg_i32( +; CHECK-NEXT: [[NEG:%.*]] = sub i32 0, [[X:%.*]] +; CHECK-NEXT: [[MASK:%.*]] = and i32 [[NEG]], [[X]] +; CHECK-NEXT: [[DEC:%.*]] = add i32 [[MASK]], -1 +; CHECK-NEXT: ret i32 [[DEC]] +; + %neg = sub i32 0, %X + %mask = and i32 %X, %neg + %dec = add i32 %mask, -1 + ret i32 %dec +} + +define i32 @dec_commute_mask_neg_i32(i32 %X) { +; CHECK-LABEL: @dec_commute_mask_neg_i32( +; CHECK-NEXT: [[NEG:%.*]] = sub i32 0, [[X:%.*]] +; CHECK-NEXT: [[MASK:%.*]] = and i32 [[NEG]], [[X]] +; CHECK-NEXT: [[DEC:%.*]] = add i32 [[MASK]], -1 +; CHECK-NEXT: ret i32 [[DEC]] +; + %neg = sub i32 0, %X + %mask = and i32 %neg, %X + %dec = add i32 -1, %mask + ret i32 %dec +} + +define i32 @dec_mask_neg_multiuse_i32(i32 %X) { +; CHECK-LABEL: @dec_mask_neg_multiuse_i32( +; CHECK-NEXT: [[NEG:%.*]] = sub i32 0, [[X:%.*]] +; CHECK-NEXT: [[MASK:%.*]] = and i32 [[NEG]], [[X]] +; CHECK-NEXT: [[DEC:%.*]] = add i32 [[MASK]], -1 +; CHECK-NEXT: call void @use(i32 [[NEG]]) +; CHECK-NEXT: ret i32 [[DEC]] +; + %neg = sub i32 0, %X + %mask = and i32 %neg, %X + %dec = add i32 %mask, -1 + call void @use(i32 %neg) + ret i32 %dec +} + +define i32 @dec_mask_multiuse_neg_i32(i32 %X) { +; CHECK-LABEL: @dec_mask_multiuse_neg_i32( +; CHECK-NEXT: [[NEG:%.*]] = sub i32 0, [[X:%.*]] +; CHECK-NEXT: [[MASK:%.*]] = and i32 [[NEG]], [[X]] +; CHECK-NEXT: [[DEC:%.*]] = add i32 [[MASK]], -1 +; CHECK-NEXT: call void @use(i32 [[MASK]]) +; CHECK-NEXT: ret i32 [[DEC]] +; + %neg = sub i32 0, %X + %mask = and i32 %neg, %X + %dec = add i32 %mask, -1 + call void @use(i32 %mask) + ret i32 %dec +} + +define <2 x i32> @dec_mask_neg_v2i32(<2 x i32> %X) { +; CHECK-LABEL: @dec_mask_neg_v2i32( +; CHECK-NEXT: [[NEG:%.*]] = sub <2 x i32> zeroinitializer, [[X:%.*]] +; CHECK-NEXT: [[MASK:%.*]] = and <2 x i32> [[NEG]], [[X]] +; CHECK-NEXT: [[DEC:%.*]] = add <2 x i32> [[MASK]], +; CHECK-NEXT: ret <2 x i32> [[DEC]] +; + %neg = sub <2 x i32> zeroinitializer, %X + %mask = and <2 x i32> %neg, %X + %dec = add <2 x i32> %mask, + ret <2 x i32> %dec +} + +define <2 x i32> @dec_mask_neg_v2i32_undef(<2 x i32> %X) { +; CHECK-LABEL: @dec_mask_neg_v2i32_undef( +; CHECK-NEXT: [[NEG:%.*]] = sub <2 x i32> zeroinitializer, [[X:%.*]] +; CHECK-NEXT: [[MASK:%.*]] = and <2 x i32> [[NEG]], [[X]] +; CHECK-NEXT: [[DEC:%.*]] = add <2 x i32> [[MASK]], +; CHECK-NEXT: ret <2 x i32> [[DEC]] +; + %neg = sub <2 x i32> zeroinitializer, %X + %mask = and <2 x i32> %neg, %X + %dec = add <2 x i32> %mask, + ret <2 x i32> %dec +} + +define <2 x i32> @dec_mask_multiuse_neg_multiuse_v2i32(<2 x i32> %X) { +; CHECK-LABEL: @dec_mask_multiuse_neg_multiuse_v2i32( +; CHECK-NEXT: [[NEG:%.*]] = sub <2 x i32> zeroinitializer, [[X:%.*]] +; CHECK-NEXT: [[MASK:%.*]] = and <2 x i32> [[NEG]], [[X]] +; CHECK-NEXT: [[DEC:%.*]] = add <2 x i32> [[MASK]], +; CHECK-NEXT: call void @usev(<2 x i32> [[NEG]]) +; CHECK-NEXT: call void @usev(<2 x i32> [[MASK]]) +; CHECK-NEXT: ret <2 x i32> [[DEC]] +; + %neg = sub <2 x i32> zeroinitializer, %X + %mask = and <2 x i32> %neg, %X + %dec = add <2 x i32> %mask, + call void @usev(<2 x i32> %neg) + call void @usev(<2 x i32> %mask) + ret <2 x i32> %dec +} + +declare void @use(i32) +declare void @usev(<2 x i32>)