1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt -bdce -S < %s | FileCheck %s 3 4; Funnel shift based rotate test cases from PR39771 5 6declare i32 @llvm.fshr.i32(i32, i32, i32) 7declare <2 x i32> @llvm.fshr.v2i32(<2 x i32>, <2 x i32>, <2 x i32>) 8 9; First fshr operand is dead. 10define i32 @pr39771_fshr_multi_use_instr(i32 %a) { 11; CHECK-LABEL: @pr39771_fshr_multi_use_instr( 12; CHECK-NEXT: [[X:%.*]] = or i32 [[A:%.*]], 0 13; CHECK-NEXT: [[B:%.*]] = tail call i32 @llvm.fshr.i32(i32 0, i32 [[X]], i32 1) 14; CHECK-NEXT: [[C:%.*]] = lshr i32 [[B]], 23 15; CHECK-NEXT: [[D:%.*]] = xor i32 [[C]], [[B]] 16; CHECK-NEXT: [[E:%.*]] = and i32 [[D]], 31 17; CHECK-NEXT: ret i32 [[E]] 18; 19 %x = or i32 %a, 0 20 %b = tail call i32 @llvm.fshr.i32(i32 %x, i32 %x, i32 1) 21 %c = lshr i32 %b, 23 22 %d = xor i32 %c, %b 23 %e = and i32 %d, 31 24 ret i32 %e 25} 26 27; First fshr operand is dead (vector variant). 28define <2 x i32> @pr39771_fshr_multi_use_instr_vec(<2 x i32> %a) { 29; CHECK-LABEL: @pr39771_fshr_multi_use_instr_vec( 30; CHECK-NEXT: [[X:%.*]] = or <2 x i32> [[A:%.*]], zeroinitializer 31; CHECK-NEXT: [[B:%.*]] = tail call <2 x i32> @llvm.fshr.v2i32(<2 x i32> zeroinitializer, <2 x i32> [[X]], <2 x i32> <i32 1, i32 1>) 32; CHECK-NEXT: [[C:%.*]] = lshr <2 x i32> [[B]], <i32 23, i32 23> 33; CHECK-NEXT: [[D:%.*]] = xor <2 x i32> [[C]], [[B]] 34; CHECK-NEXT: [[E:%.*]] = and <2 x i32> [[D]], <i32 31, i32 31> 35; CHECK-NEXT: ret <2 x i32> [[E]] 36; 37 %x = or <2 x i32> %a, zeroinitializer 38 %b = tail call <2 x i32> @llvm.fshr.v2i32(<2 x i32> %x, <2 x i32> %x, <2 x i32> <i32 1, i32 1>) 39 %c = lshr <2 x i32> %b, <i32 23, i32 23> 40 %d = xor <2 x i32> %c, %b 41 %e = and <2 x i32> %d, <i32 31, i32 31> 42 ret <2 x i32> %e 43} 44 45; First fshr operand is dead, but it comes from an argument, not instruction. 46define i32 @pr39771_fshr_multi_use_arg(i32 %a) { 47; CHECK-LABEL: @pr39771_fshr_multi_use_arg( 48; CHECK-NEXT: [[B:%.*]] = tail call i32 @llvm.fshr.i32(i32 0, i32 [[A:%.*]], i32 1) 49; CHECK-NEXT: [[C:%.*]] = lshr i32 [[B]], 23 50; CHECK-NEXT: [[D:%.*]] = xor i32 [[C]], [[B]] 51; CHECK-NEXT: [[E:%.*]] = and i32 [[D]], 31 52; CHECK-NEXT: ret i32 [[E]] 53; 54 %b = tail call i32 @llvm.fshr.i32(i32 %a, i32 %a, i32 1) 55 %c = lshr i32 %b, 23 56 %d = xor i32 %c, %b 57 %e = and i32 %d, 31 58 ret i32 %e 59} 60 61define i32 @pr39771_expanded_fshr_multi_use(i32 %a) { 62; CHECK-LABEL: @pr39771_expanded_fshr_multi_use( 63; CHECK-NEXT: [[TMP:%.*]] = lshr i32 [[A:%.*]], 1 64; CHECK-NEXT: [[TMP2:%.*]] = shl i32 0, 31 65; CHECK-NEXT: [[B:%.*]] = or i32 [[TMP]], [[TMP2]] 66; CHECK-NEXT: [[C:%.*]] = lshr i32 [[B]], 23 67; CHECK-NEXT: [[D:%.*]] = xor i32 [[C]], [[B]] 68; CHECK-NEXT: [[E:%.*]] = and i32 [[D]], 31 69; CHECK-NEXT: ret i32 [[E]] 70; 71 %tmp = lshr i32 %a, 1 72 %tmp2 = shl i32 %a, 31 73 %b = or i32 %tmp, %tmp2 74 %c = lshr i32 %b, 23 75 %d = xor i32 %c, %b 76 %e = and i32 %d, 31 77 ret i32 %e 78} 79 80; %b operand of %c will be dead initially, but later found live. 81define void @dead_use_invalidation(i32 %a) { 82; CHECK-LABEL: @dead_use_invalidation( 83; CHECK-NEXT: [[B:%.*]] = or i32 [[A:%.*]], 0 84; CHECK-NEXT: [[C:%.*]] = shl i32 [[B]], 31 85; CHECK-NEXT: [[D:%.*]] = and i32 [[C]], 1 86; CHECK-NEXT: [[E:%.*]] = or i32 [[C]], 0 87; CHECK-NEXT: [[F:%.*]] = or i32 [[D]], 0 88; CHECK-NEXT: call void @dummy(i32 [[E]]) 89; CHECK-NEXT: call void @dummy(i32 [[F]]) 90; CHECK-NEXT: call void @dummy(i32 [[B]]) 91; CHECK-NEXT: ret void 92; 93 %b = or i32 %a, 0 94 %c = shl i32 %b, 31 95 %d = and i32 %c, 1 96 %e = or i32 %c, 0 97 %f = or i32 %d, 0 98 call void @dummy(i32 %e) 99 call void @dummy(i32 %f) 100 call void @dummy(i32 %b) 101 ret void 102} 103declare void @dummy(i32) 104