| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py |
| ; RUN: opt < %s -S -passes=instcombine | FileCheck %s |
| |
| ; |
| ; Canonicalize ((X & -X) - 1) --> ((X - 1) & ~X) |
| ; |
| |
| define i32 @dec_mask_neg_i32(i32 %X) { |
| ; CHECK-LABEL: @dec_mask_neg_i32( |
| ; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[X:%.*]], -1 |
| ; CHECK-NEXT: [[TMP2:%.*]] = xor i32 [[X]], -1 |
| ; CHECK-NEXT: [[DEC:%.*]] = and i32 [[TMP1]], [[TMP2]] |
| ; 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 %A) { |
| ; CHECK-LABEL: @dec_mask_commute_neg_i32( |
| ; CHECK-NEXT: [[X:%.*]] = sdiv i32 42, [[A:%.*]] |
| ; CHECK-NEXT: [[TMP1:%.*]] = add nsw i32 [[X]], -1 |
| ; CHECK-NEXT: [[TMP2:%.*]] = xor i32 [[X]], -1 |
| ; CHECK-NEXT: [[DEC:%.*]] = and i32 [[TMP1]], [[TMP2]] |
| ; CHECK-NEXT: ret i32 [[DEC]] |
| ; |
| %X = sdiv i32 42, %A ; thwart complexity-based canonicalization |
| %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: [[TMP1:%.*]] = add i32 [[X:%.*]], -1 |
| ; CHECK-NEXT: [[TMP2:%.*]] = xor i32 [[X]], -1 |
| ; CHECK-NEXT: [[DEC:%.*]] = and i32 [[TMP1]], [[TMP2]] |
| ; 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: [[TMP1:%.*]] = add <2 x i32> [[X:%.*]], <i32 -1, i32 -1> |
| ; CHECK-NEXT: [[TMP2:%.*]] = xor <2 x i32> [[X]], <i32 -1, i32 -1> |
| ; CHECK-NEXT: [[DEC:%.*]] = and <2 x i32> [[TMP1]], [[TMP2]] |
| ; 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, <i32 -1, i32 -1> |
| 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: [[TMP1:%.*]] = add <2 x i32> [[X:%.*]], <i32 -1, i32 -1> |
| ; CHECK-NEXT: [[TMP2:%.*]] = xor <2 x i32> [[X]], <i32 -1, i32 -1> |
| ; CHECK-NEXT: [[DEC:%.*]] = and <2 x i32> [[TMP1]], [[TMP2]] |
| ; 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, <i32 -1, i32 undef> |
| 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]], <i32 -1, i32 -1> |
| ; 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, <i32 -1, i32 -1> |
| 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>) |