; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt < %s -instcombine -S | FileCheck %s declare i32 @llvm.fshl.i32(i32, i32, i32) declare i33 @llvm.fshr.i33(i33, i33, i33) declare <2 x i32> @llvm.fshr.v2i32(<2 x i32>, <2 x i32>, <2 x i32>) declare <2 x i31> @llvm.fshl.v2i31(<2 x i31>, <2 x i31>, <2 x i31>) ; If the shift mask doesn't include any demanded bits, the funnel shift can be eliminated. define i32 @fshl_mask_simplify1(i32 %x, i32 %y, i32 %sh) { ; CHECK-LABEL: @fshl_mask_simplify1( ; CHECK-NEXT: ret i32 [[X:%.*]] ; %maskedsh = and i32 %sh, 32 %r = call i32 @llvm.fshl.i32(i32 %x, i32 %y, i32 %maskedsh) ret i32 %r } define <2 x i32> @fshr_mask_simplify2(<2 x i32> %x, <2 x i32> %y, <2 x i32> %sh) { ; CHECK-LABEL: @fshr_mask_simplify2( ; CHECK-NEXT: ret <2 x i32> [[Y:%.*]] ; %maskedsh = and <2 x i32> %sh, %r = call <2 x i32> @llvm.fshr.v2i32(<2 x i32> %x, <2 x i32> %y, <2 x i32> %maskedsh) ret <2 x i32> %r } ; Negative test. define i32 @fshl_mask_simplify3(i32 %x, i32 %y, i32 %sh) { ; CHECK-LABEL: @fshl_mask_simplify3( ; CHECK-NEXT: [[MASKEDSH:%.*]] = and i32 [[SH:%.*]], 16 ; CHECK-NEXT: [[R:%.*]] = call i32 @llvm.fshl.i32(i32 [[X:%.*]], i32 [[Y:%.*]], i32 [[MASKEDSH]]) ; CHECK-NEXT: ret i32 [[R]] ; %maskedsh = and i32 %sh, 16 %r = call i32 @llvm.fshl.i32(i32 %x, i32 %y, i32 %maskedsh) ret i32 %r } ; Check again with weird bitwidths - the analysis is invalid with non-power-of-2. define i33 @fshr_mask_simplify1(i33 %x, i33 %y, i33 %sh) { ; CHECK-LABEL: @fshr_mask_simplify1( ; CHECK-NEXT: [[MASKEDSH:%.*]] = and i33 [[SH:%.*]], 64 ; CHECK-NEXT: [[R:%.*]] = call i33 @llvm.fshr.i33(i33 [[X:%.*]], i33 [[Y:%.*]], i33 [[MASKEDSH]]) ; CHECK-NEXT: ret i33 [[R]] ; %maskedsh = and i33 %sh, 64 %r = call i33 @llvm.fshr.i33(i33 %x, i33 %y, i33 %maskedsh) ret i33 %r } ; Check again with weird bitwidths - the analysis is invalid with non-power-of-2. define <2 x i31> @fshl_mask_simplify2(<2 x i31> %x, <2 x i31> %y, <2 x i31> %sh) { ; CHECK-LABEL: @fshl_mask_simplify2( ; CHECK-NEXT: [[MASKEDSH:%.*]] = and <2 x i31> [[SH:%.*]], ; CHECK-NEXT: [[R:%.*]] = call <2 x i31> @llvm.fshl.v2i31(<2 x i31> [[X:%.*]], <2 x i31> [[Y:%.*]], <2 x i31> [[MASKEDSH]]) ; CHECK-NEXT: ret <2 x i31> [[R]] ; %maskedsh = and <2 x i31> %sh, %r = call <2 x i31> @llvm.fshl.v2i31(<2 x i31> %x, <2 x i31> %y, <2 x i31> %maskedsh) ret <2 x i31> %r } ; Check again with weird bitwidths - the analysis is invalid with non-power-of-2. define i33 @fshr_mask_simplify3(i33 %x, i33 %y, i33 %sh) { ; CHECK-LABEL: @fshr_mask_simplify3( ; CHECK-NEXT: [[MASKEDSH:%.*]] = and i33 [[SH:%.*]], 32 ; CHECK-NEXT: [[R:%.*]] = call i33 @llvm.fshr.i33(i33 [[X:%.*]], i33 [[Y:%.*]], i33 [[MASKEDSH]]) ; CHECK-NEXT: ret i33 [[R]] ; %maskedsh = and i33 %sh, 32 %r = call i33 @llvm.fshr.i33(i33 %x, i33 %y, i33 %maskedsh) ret i33 %r } ; This mask op is unnecessary. define i32 @fshl_mask_not_required(i32 %x, i32 %y, i32 %sh) { ; CHECK-LABEL: @fshl_mask_not_required( ; CHECK-NEXT: [[R:%.*]] = call i32 @llvm.fshl.i32(i32 [[X:%.*]], i32 [[Y:%.*]], i32 [[SH:%.*]]) ; CHECK-NEXT: ret i32 [[R]] ; %maskedsh = and i32 %sh, 31 %r = call i32 @llvm.fshl.i32(i32 %x, i32 %y, i32 %maskedsh) ret i32 %r } ; This mask op can be reduced. define i32 @fshl_mask_reduce_constant(i32 %x, i32 %y, i32 %sh) { ; CHECK-LABEL: @fshl_mask_reduce_constant( ; CHECK-NEXT: [[MASKEDSH:%.*]] = and i32 [[SH:%.*]], 1 ; CHECK-NEXT: [[R:%.*]] = call i32 @llvm.fshl.i32(i32 [[X:%.*]], i32 [[Y:%.*]], i32 [[MASKEDSH]]) ; CHECK-NEXT: ret i32 [[R]] ; %maskedsh = and i32 %sh, 33 %r = call i32 @llvm.fshl.i32(i32 %x, i32 %y, i32 %maskedsh) ret i32 %r } ; But this mask op is required. define i32 @fshl_mask_negative(i32 %x, i32 %y, i32 %sh) { ; CHECK-LABEL: @fshl_mask_negative( ; CHECK-NEXT: [[MASKEDSH:%.*]] = and i32 [[SH:%.*]], 15 ; CHECK-NEXT: [[R:%.*]] = call i32 @llvm.fshl.i32(i32 [[X:%.*]], i32 [[Y:%.*]], i32 [[MASKEDSH]]) ; CHECK-NEXT: ret i32 [[R]] ; %maskedsh = and i32 %sh, 15 %r = call i32 @llvm.fshl.i32(i32 %x, i32 %y, i32 %maskedsh) ret i32 %r } ; The transform is not limited to mask ops. define <2 x i32> @fshr_set_but_not_demanded_vec(<2 x i32> %x, <2 x i32> %y, <2 x i32> %sh) { ; CHECK-LABEL: @fshr_set_but_not_demanded_vec( ; CHECK-NEXT: [[R:%.*]] = call <2 x i32> @llvm.fshr.v2i32(<2 x i32> [[X:%.*]], <2 x i32> [[Y:%.*]], <2 x i32> [[SH:%.*]]) ; CHECK-NEXT: ret <2 x i32> [[R]] ; %bogusbits = or <2 x i32> %sh, %r = call <2 x i32> @llvm.fshr.v2i32(<2 x i32> %x, <2 x i32> %y, <2 x i32> %bogusbits) ret <2 x i32> %r } ; Check again with weird bitwidths - the analysis is invalid with non-power-of-2. define <2 x i31> @fshl_set_but_not_demanded_vec(<2 x i31> %x, <2 x i31> %y, <2 x i31> %sh) { ; CHECK-LABEL: @fshl_set_but_not_demanded_vec( ; CHECK-NEXT: [[BOGUSBITS:%.*]] = or <2 x i31> [[SH:%.*]], ; CHECK-NEXT: [[R:%.*]] = call <2 x i31> @llvm.fshl.v2i31(<2 x i31> [[X:%.*]], <2 x i31> [[Y:%.*]], <2 x i31> [[BOGUSBITS]]) ; CHECK-NEXT: ret <2 x i31> [[R]] ; %bogusbits = or <2 x i31> %sh, %r = call <2 x i31> @llvm.fshl.v2i31(<2 x i31> %x, <2 x i31> %y, <2 x i31> %bogusbits) ret <2 x i31> %r } ; Simplify one undef or zero operand and constant shift amount. define i32 @fshl_op0_undef(i32 %x) { ; CHECK-LABEL: @fshl_op0_undef( ; CHECK-NEXT: [[R:%.*]] = lshr i32 [[X:%.*]], 25 ; CHECK-NEXT: ret i32 [[R]] ; %r = call i32 @llvm.fshl.i32(i32 undef, i32 %x, i32 7) ret i32 %r } define i32 @fshl_op0_zero(i32 %x) { ; CHECK-LABEL: @fshl_op0_zero( ; CHECK-NEXT: [[R:%.*]] = lshr i32 [[X:%.*]], 25 ; CHECK-NEXT: ret i32 [[R]] ; %r = call i32 @llvm.fshl.i32(i32 0, i32 %x, i32 7) ret i32 %r } define i33 @fshr_op0_undef(i33 %x) { ; CHECK-LABEL: @fshr_op0_undef( ; CHECK-NEXT: [[R:%.*]] = lshr i33 [[X:%.*]], 7 ; CHECK-NEXT: ret i33 [[R]] ; %r = call i33 @llvm.fshr.i33(i33 undef, i33 %x, i33 7) ret i33 %r } define i33 @fshr_op0_zero(i33 %x) { ; CHECK-LABEL: @fshr_op0_zero( ; CHECK-NEXT: [[R:%.*]] = lshr i33 [[X:%.*]], 7 ; CHECK-NEXT: ret i33 [[R]] ; %r = call i33 @llvm.fshr.i33(i33 0, i33 %x, i33 7) ret i33 %r } define i32 @fshl_op1_undef(i32 %x) { ; CHECK-LABEL: @fshl_op1_undef( ; CHECK-NEXT: [[R:%.*]] = shl i32 [[X:%.*]], 7 ; CHECK-NEXT: ret i32 [[R]] ; %r = call i32 @llvm.fshl.i32(i32 %x, i32 undef, i32 7) ret i32 %r } define i32 @fshl_op1_zero(i32 %x) { ; CHECK-LABEL: @fshl_op1_zero( ; CHECK-NEXT: [[R:%.*]] = shl i32 [[X:%.*]], 7 ; CHECK-NEXT: ret i32 [[R]] ; %r = call i32 @llvm.fshl.i32(i32 %x, i32 0, i32 7) ret i32 %r } define i33 @fshr_op1_undef(i33 %x) { ; CHECK-LABEL: @fshr_op1_undef( ; CHECK-NEXT: [[R:%.*]] = shl i33 [[X:%.*]], 26 ; CHECK-NEXT: ret i33 [[R]] ; %r = call i33 @llvm.fshr.i33(i33 %x, i33 undef, i33 7) ret i33 %r } define i33 @fshr_op1_zero(i33 %x) { ; CHECK-LABEL: @fshr_op1_zero( ; CHECK-NEXT: [[R:%.*]] = shl i33 [[X:%.*]], 26 ; CHECK-NEXT: ret i33 [[R]] ; %r = call i33 @llvm.fshr.i33(i33 %x, i33 0, i33 7) ret i33 %r } define <2 x i31> @fshl_op0_zero_vec(<2 x i31> %x) { ; CHECK-LABEL: @fshl_op0_zero_vec( ; CHECK-NEXT: [[R:%.*]] = lshr <2 x i31> [[X:%.*]], ; CHECK-NEXT: ret <2 x i31> [[R]] ; %r = call <2 x i31> @llvm.fshl.v2i31(<2 x i31> zeroinitializer, <2 x i31> %x, <2 x i31> ) ret <2 x i31> %r } define <2 x i31> @fshl_op1_undef_vec(<2 x i31> %x) { ; CHECK-LABEL: @fshl_op1_undef_vec( ; CHECK-NEXT: [[R:%.*]] = shl <2 x i31> [[X:%.*]], ; CHECK-NEXT: ret <2 x i31> [[R]] ; %r = call <2 x i31> @llvm.fshl.v2i31(<2 x i31> %x, <2 x i31> undef, <2 x i31> ) ret <2 x i31> %r } define <2 x i32> @fshr_op0_undef_vec(<2 x i32> %x) { ; CHECK-LABEL: @fshr_op0_undef_vec( ; CHECK-NEXT: [[R:%.*]] = lshr <2 x i32> [[X:%.*]], ; CHECK-NEXT: ret <2 x i32> [[R]] ; %r = call <2 x i32> @llvm.fshr.v2i32(<2 x i32> undef, <2 x i32> %x, <2 x i32> ) ret <2 x i32> %r } define <2 x i32> @fshr_op1_zero_vec(<2 x i32> %x) { ; CHECK-LABEL: @fshr_op1_zero_vec( ; CHECK-NEXT: [[R:%.*]] = shl <2 x i32> [[X:%.*]], ; CHECK-NEXT: ret <2 x i32> [[R]] ; %r = call <2 x i32> @llvm.fshr.v2i32(<2 x i32> %x, <2 x i32> zeroinitializer, <2 x i32> ) ret <2 x i32> %r } ; Only demand bits from one of the operands. define i32 @fshl_only_op0_demanded(i32 %x, i32 %y) { ; CHECK-LABEL: @fshl_only_op0_demanded( ; CHECK-NEXT: [[Z:%.*]] = shl i32 [[X:%.*]], 7 ; CHECK-NEXT: [[R:%.*]] = and i32 [[Z]], 128 ; CHECK-NEXT: ret i32 [[R]] ; %z = call i32 @llvm.fshl.i32(i32 %x, i32 %y, i32 7) %r = and i32 %z, 128 ret i32 %r } define i32 @fshl_only_op1_demanded(i32 %x, i32 %y) { ; CHECK-LABEL: @fshl_only_op1_demanded( ; CHECK-NEXT: [[Z:%.*]] = lshr i32 [[Y:%.*]], 25 ; CHECK-NEXT: [[R:%.*]] = and i32 [[Z]], 63 ; CHECK-NEXT: ret i32 [[R]] ; %z = call i32 @llvm.fshl.i32(i32 %x, i32 %y, i32 7) %r = and i32 %z, 63 ret i32 %r } define i33 @fshr_only_op1_demanded(i33 %x, i33 %y) { ; CHECK-LABEL: @fshr_only_op1_demanded( ; CHECK-NEXT: [[Z:%.*]] = lshr i33 [[Y:%.*]], 7 ; CHECK-NEXT: [[R:%.*]] = and i33 [[Z]], 12392 ; CHECK-NEXT: ret i33 [[R]] ; %z = call i33 @llvm.fshr.i33(i33 %x, i33 %y, i33 7) %r = and i33 %z, 12392 ret i33 %r } define i33 @fshr_only_op0_demanded(i33 %x, i33 %y) { ; CHECK-LABEL: @fshr_only_op0_demanded( ; CHECK-NEXT: [[TMP1:%.*]] = lshr i33 [[X:%.*]], 4 ; CHECK-NEXT: [[R:%.*]] = and i33 [[TMP1]], 7 ; CHECK-NEXT: ret i33 [[R]] ; %z = call i33 @llvm.fshr.i33(i33 %x, i33 %y, i33 7) %r = lshr i33 %z, 30 ret i33 %r } define <2 x i31> @fshl_only_op1_demanded_vec_splat(<2 x i31> %x, <2 x i31> %y) { ; CHECK-LABEL: @fshl_only_op1_demanded_vec_splat( ; CHECK-NEXT: [[Z:%.*]] = lshr <2 x i31> [[Y:%.*]], ; CHECK-NEXT: [[R:%.*]] = and <2 x i31> [[Z]], ; CHECK-NEXT: ret <2 x i31> [[R]] ; %z = call <2 x i31> @llvm.fshl.v2i31(<2 x i31> %x, <2 x i31> %y, <2 x i31> ) %r = and <2 x i31> %z, ret <2 x i31> %r } ; The shift modulo bitwidth is the same for all vector elements, but this is not simplified yet. define <2 x i31> @fshl_only_op1_demanded_vec_nonsplat(<2 x i31> %x, <2 x i31> %y) { ; CHECK-LABEL: @fshl_only_op1_demanded_vec_nonsplat( ; CHECK-NEXT: [[Z:%.*]] = call <2 x i31> @llvm.fshl.v2i31(<2 x i31> [[X:%.*]], <2 x i31> [[Y:%.*]], <2 x i31> ) ; CHECK-NEXT: [[R:%.*]] = and <2 x i31> [[Z]], ; CHECK-NEXT: ret <2 x i31> [[R]] ; %z = call <2 x i31> @llvm.fshl.v2i31(<2 x i31> %x, <2 x i31> %y, <2 x i31> ) %r = and <2 x i31> %z, ret <2 x i31> %r } ; Demand bits from both operands -- cannot simplify. define i32 @fshl_both_ops_demanded(i32 %x, i32 %y) { ; CHECK-LABEL: @fshl_both_ops_demanded( ; CHECK-NEXT: [[Z:%.*]] = call i32 @llvm.fshl.i32(i32 [[X:%.*]], i32 [[Y:%.*]], i32 7) ; CHECK-NEXT: [[R:%.*]] = and i32 [[Z]], 192 ; CHECK-NEXT: ret i32 [[R]] ; %z = call i32 @llvm.fshl.i32(i32 %x, i32 %y, i32 7) %r = and i32 %z, 192 ret i32 %r } define i33 @fshr_both_ops_demanded(i33 %x, i33 %y) { ; CHECK-LABEL: @fshr_both_ops_demanded( ; CHECK-NEXT: [[Z:%.*]] = call i33 @llvm.fshr.i33(i33 [[X:%.*]], i33 [[Y:%.*]], i33 26) ; CHECK-NEXT: [[R:%.*]] = and i33 [[Z]], 192 ; CHECK-NEXT: ret i33 [[R]] ; %z = call i33 @llvm.fshr.i33(i33 %x, i33 %y, i33 26) %r = and i33 %z, 192 ret i33 %r } ; Both operands are demanded, but there are known bits. define i32 @fshl_known_bits(i32 %x, i32 %y) { ; CHECK-LABEL: @fshl_known_bits( ; CHECK-NEXT: ret i32 128 ; %x2 = or i32 %x, 1 ; lo bit set %y2 = lshr i32 %y, 1 ; hi bit clear %z = call i32 @llvm.fshl.i32(i32 %x2, i32 %y2, i32 7) %r = and i32 %z, 192 ret i32 %r } define i33 @fshr_known_bits(i33 %x, i33 %y) { ; CHECK-LABEL: @fshr_known_bits( ; CHECK-NEXT: ret i33 128 ; %x2 = or i33 %x, 1 ; lo bit set %y2 = lshr i33 %y, 1 ; hi bit set %z = call i33 @llvm.fshr.i33(i33 %x2, i33 %y2, i33 26) %r = and i33 %z, 192 ret i33 %r } ; This case fails to simplify due to multiple uses. define i33 @fshr_multi_use(i33 %a) { ; CHECK-LABEL: @fshr_multi_use( ; CHECK-NEXT: [[B:%.*]] = tail call i33 @llvm.fshr.i33(i33 [[A:%.*]], i33 [[A]], i33 1) ; CHECK-NEXT: [[C:%.*]] = lshr i33 [[B]], 23 ; CHECK-NEXT: [[D:%.*]] = xor i33 [[C]], [[B]] ; CHECK-NEXT: [[E:%.*]] = and i33 [[D]], 31 ; CHECK-NEXT: ret i33 [[E]] ; %b = tail call i33 @llvm.fshr.i33(i33 %a, i33 %a, i33 1) %c = lshr i33 %b, 23 %d = xor i33 %c, %b %e = and i33 %d, 31 ret i33 %e } ; This demonstrates the same simplification working if the fshr intrinsic ; is expanded into shifts and or. define i33 @expanded_fshr_multi_use(i33 %a) { ; CHECK-LABEL: @expanded_fshr_multi_use( ; CHECK-NEXT: [[TMP:%.*]] = lshr i33 [[A:%.*]], 1 ; CHECK-NEXT: [[C:%.*]] = lshr i33 [[A]], 24 ; CHECK-NEXT: [[D:%.*]] = xor i33 [[C]], [[TMP]] ; CHECK-NEXT: [[E:%.*]] = and i33 [[D]], 31 ; CHECK-NEXT: ret i33 [[E]] ; %tmp = lshr i33 %a, 1 %tmp2 = shl i33 %a, 32 %b = or i33 %tmp, %tmp2 %c = lshr i33 %b, 23 %d = xor i33 %c, %b %e = and i33 %d, 31 ret i33 %e } declare i16 @llvm.fshl.i16(i16, i16, i16) declare i16 @llvm.fshr.i16(i16, i16, i16) ; Special-case: rotate a 16-bit value left/right by 8-bits is bswap. define i16 @fshl_bswap(i16 %x) { ; CHECK-LABEL: @fshl_bswap( ; CHECK-NEXT: [[R:%.*]] = call i16 @llvm.fshl.i16(i16 [[X:%.*]], i16 [[X]], i16 8) ; CHECK-NEXT: ret i16 [[R]] ; %r = call i16 @llvm.fshl.i16(i16 %x, i16 %x, i16 8) ret i16 %r } define i16 @fshr_bswap(i16 %x) { ; CHECK-LABEL: @fshr_bswap( ; CHECK-NEXT: [[R:%.*]] = call i16 @llvm.fshr.i16(i16 [[X:%.*]], i16 [[X]], i16 8) ; CHECK-NEXT: ret i16 [[R]] ; %r = call i16 @llvm.fshr.i16(i16 %x, i16 %x, i16 8) ret i16 %r }