; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt -passes=aggressive-instcombine -mtriple=x86_64 -mattr=+lzcnt -S < %s | FileCheck %s @log2.table = internal unnamed_addr constant [32 x i8] c"\05\09\01\0A\0D\15\02\1D\0B\0E\10\12\16\19\03\1E\08\0C\14\1C\0F\11\18\07\13\1B\17\06\1A\05\04\1F", align 1 ;; This is a negative test with a wrong table constant. define i32 @log2_32(i32 %v) { ; CHECK-LABEL: @log2_32( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[SHR:%.*]] = lshr i32 [[V:%.*]], 1 ; CHECK-NEXT: [[OR:%.*]] = or i32 [[SHR]], [[V]] ; CHECK-NEXT: [[SHR1:%.*]] = lshr i32 [[OR]], 2 ; CHECK-NEXT: [[OR2:%.*]] = or i32 [[SHR1]], [[OR]] ; CHECK-NEXT: [[SHR3:%.*]] = lshr i32 [[OR2]], 4 ; CHECK-NEXT: [[OR4:%.*]] = or i32 [[SHR3]], [[OR2]] ; CHECK-NEXT: [[SHR5:%.*]] = lshr i32 [[OR4]], 8 ; CHECK-NEXT: [[OR6:%.*]] = or i32 [[SHR5]], [[OR4]] ; CHECK-NEXT: [[SHR7:%.*]] = lshr i32 [[OR6]], 16 ; CHECK-NEXT: [[OR8:%.*]] = or i32 [[SHR7]], [[OR6]] ; CHECK-NEXT: [[MUL:%.*]] = mul i32 [[OR8]], 130329821 ; CHECK-NEXT: [[SHR9:%.*]] = lshr i32 [[MUL]], 27 ; CHECK-NEXT: [[IDXPROM:%.*]] = zext nneg i32 [[SHR9]] to i64 ; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [32 x i8], ptr @log2.table, i64 0, i64 [[IDXPROM]] ; CHECK-NEXT: [[TMP4:%.*]] = load i8, ptr [[ARRAYIDX]], align 1 ; CHECK-NEXT: [[CONV:%.*]] = zext i8 [[TMP4]] to i32 ; CHECK-NEXT: ret i32 [[CONV]] ; entry: %shr = lshr i32 %v, 1 %or = or i32 %shr, %v %shr1 = lshr i32 %or, 2 %or2 = or i32 %shr1, %or %shr3 = lshr i32 %or2, 4 %or4 = or i32 %shr3, %or2 %shr5 = lshr i32 %or4, 8 %or6 = or i32 %shr5, %or4 %shr7 = lshr i32 %or6, 16 %or8 = or i32 %shr7, %or6 %mul = mul i32 %or8, 130329821 %shr9 = lshr i32 %mul, 27 %idxprom = zext nneg i32 %shr9 to i64 %arrayidx = getelementptr inbounds [32 x i8], ptr @log2.table, i64 0, i64 %idxprom %0 = load i8, ptr %arrayidx, align 1 %conv = zext i8 %0 to i32 ret i32 %conv } @log2_2.table = internal unnamed_addr constant [32 x i8] c"\00\09\01\0A\0D\15\02\1D\0B\0E\10\12\16\19\03\1E\08\0C\14\1C\0F\11\18\07\13\1B\17\06\1A\05\04\1F", align 1 ;; These are some negative tests with a wrong instruction sequences. define i32 @log2_32_2(i32 %v) { ; CHECK-LABEL: @log2_32_2( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[SHR:%.*]] = lshr i32 [[V:%.*]], 1 ; CHECK-NEXT: [[OR:%.*]] = or i32 [[SHR]], [[V]] ; CHECK-NEXT: [[SHR1:%.*]] = lshr i32 [[OR]], 2 ; CHECK-NEXT: [[OR2:%.*]] = or i32 [[SHR1]], [[OR]] ; CHECK-NEXT: [[SHR3:%.*]] = lshr i32 [[OR2]], 4 ; CHECK-NEXT: [[OR4:%.*]] = or i32 [[SHR3]], [[OR2]] ; CHECK-NEXT: [[SHR5:%.*]] = lshr i32 [[OR4]], 8 ; CHECK-NEXT: [[OR6:%.*]] = or i32 [[SHR5]], [[OR4]] ; CHECK-NEXT: [[SHR7:%.*]] = lshr i32 [[OR6]], 15 ; CHECK-NEXT: [[OR8:%.*]] = or i32 [[SHR7]], [[OR6]] ; CHECK-NEXT: [[MUL:%.*]] = mul i32 [[OR8]], 130329821 ; CHECK-NEXT: [[SHR9:%.*]] = lshr i32 [[MUL]], 27 ; CHECK-NEXT: [[IDXPROM:%.*]] = zext nneg i32 [[SHR9]] to i64 ; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [32 x i8], ptr @log2_2.table, i64 0, i64 [[IDXPROM]] ; CHECK-NEXT: [[TMP0:%.*]] = load i8, ptr [[ARRAYIDX]], align 1 ; CHECK-NEXT: [[CONV:%.*]] = zext i8 [[TMP0]] to i32 ; CHECK-NEXT: ret i32 [[CONV]] ; entry: %shr = lshr i32 %v, 1 %or = or i32 %shr, %v %shr1 = lshr i32 %or, 2 %or2 = or i32 %shr1, %or %shr3 = lshr i32 %or2, 4 %or4 = or i32 %shr3, %or2 %shr5 = lshr i32 %or4, 8 %or6 = or i32 %shr5, %or4 %shr7 = lshr i32 %or6, 15 %or8 = or i32 %shr7, %or6 %mul = mul i32 %or8, 130329821 %shr9 = lshr i32 %mul, 27 %idxprom = zext nneg i32 %shr9 to i64 %arrayidx = getelementptr inbounds [32 x i8], ptr @log2_2.table, i64 0, i64 %idxprom %0 = load i8, ptr %arrayidx, align 1 %conv = zext i8 %0 to i32 ret i32 %conv } define i32 @log2_32_3(i32 %v) { ; CHECK-LABEL: @log2_32_3( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[SHR:%.*]] = lshr i32 [[V:%.*]], 1 ; CHECK-NEXT: [[OR:%.*]] = or i32 [[SHR]], [[V]] ; CHECK-NEXT: [[SHR1:%.*]] = lshr i32 [[OR]], 2 ; CHECK-NEXT: [[OR2:%.*]] = or i32 [[SHR1]], [[OR]] ; CHECK-NEXT: [[SHR3:%.*]] = lshr i32 [[OR2]], 4 ; CHECK-NEXT: [[OR4:%.*]] = or i32 [[SHR3]], [[OR2]] ; CHECK-NEXT: [[SHR5:%.*]] = lshr i32 [[OR4]], 8 ; CHECK-NEXT: [[OR6:%.*]] = or i32 [[SHR5]], [[OR4]] ; CHECK-NEXT: [[SHR7:%.*]] = lshr i32 [[OR6]], 16 ; CHECK-NEXT: [[OR8:%.*]] = or i32 [[SHR7]], [[OR6]] ; CHECK-NEXT: [[MUL:%.*]] = mul i32 [[OR8]], 130329822 ; CHECK-NEXT: [[SHR9:%.*]] = lshr i32 [[MUL]], 27 ; CHECK-NEXT: [[IDXPROM:%.*]] = zext nneg i32 [[SHR9]] to i64 ; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [32 x i8], ptr @log2_2.table, i64 0, i64 [[IDXPROM]] ; CHECK-NEXT: [[TMP0:%.*]] = load i8, ptr [[ARRAYIDX]], align 1 ; CHECK-NEXT: [[CONV:%.*]] = zext i8 [[TMP0]] to i32 ; CHECK-NEXT: ret i32 [[CONV]] ; entry: %shr = lshr i32 %v, 1 %or = or i32 %shr, %v %shr1 = lshr i32 %or, 2 %or2 = or i32 %shr1, %or %shr3 = lshr i32 %or2, 4 %or4 = or i32 %shr3, %or2 %shr5 = lshr i32 %or4, 8 %or6 = or i32 %shr5, %or4 %shr7 = lshr i32 %or6, 16 %or8 = or i32 %shr7, %or6 %mul = mul i32 %or8, 130329822 %shr9 = lshr i32 %mul, 27 %idxprom = zext nneg i32 %shr9 to i64 %arrayidx = getelementptr inbounds [32 x i8], ptr @log2_2.table, i64 0, i64 %idxprom %0 = load i8, ptr %arrayidx, align 1 %conv = zext i8 %0 to i32 ret i32 %conv } define i32 @log2_32_4(i32 %v) { ; CHECK-LABEL: @log2_32_4( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[SHR:%.*]] = lshr i32 [[V:%.*]], 1 ; CHECK-NEXT: [[OR:%.*]] = or i32 [[SHR]], [[V]] ; CHECK-NEXT: [[SHR1:%.*]] = lshr i32 [[OR]], 2 ; CHECK-NEXT: [[OR2:%.*]] = or i32 [[SHR1]], [[OR]] ; CHECK-NEXT: [[SHR3:%.*]] = lshr i32 [[OR2]], 4 ; CHECK-NEXT: [[OR4:%.*]] = or i32 [[SHR3]], [[OR2]] ; CHECK-NEXT: [[SHR5:%.*]] = lshr i32 [[OR4]], 8 ; CHECK-NEXT: [[OR6:%.*]] = or i32 [[SHR5]], [[OR4]] ; CHECK-NEXT: [[SHR7:%.*]] = lshr i32 [[OR6]], 15 ; CHECK-NEXT: [[OR8:%.*]] = or i32 [[SHR7]], [[OR6]] ; CHECK-NEXT: [[MUL:%.*]] = mul i32 [[OR8]], 130329821 ; CHECK-NEXT: [[SHR9:%.*]] = lshr i32 [[MUL]], 26 ; CHECK-NEXT: [[IDXPROM:%.*]] = zext nneg i32 [[SHR9]] to i64 ; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [32 x i8], ptr @log2_2.table, i64 0, i64 [[IDXPROM]] ; CHECK-NEXT: [[TMP0:%.*]] = load i8, ptr [[ARRAYIDX]], align 1 ; CHECK-NEXT: [[CONV:%.*]] = zext i8 [[TMP0]] to i32 ; CHECK-NEXT: ret i32 [[CONV]] ; entry: %shr = lshr i32 %v, 1 %or = or i32 %shr, %v %shr1 = lshr i32 %or, 2 %or2 = or i32 %shr1, %or %shr3 = lshr i32 %or2, 4 %or4 = or i32 %shr3, %or2 %shr5 = lshr i32 %or4, 8 %or6 = or i32 %shr5, %or4 %shr7 = lshr i32 %or6, 15 %or8 = or i32 %shr7, %or6 %mul = mul i32 %or8, 130329821 %shr9 = lshr i32 %mul, 26 %idxprom = zext nneg i32 %shr9 to i64 %arrayidx = getelementptr inbounds [32 x i8], ptr @log2_2.table, i64 0, i64 %idxprom %0 = load i8, ptr %arrayidx, align 1 %conv = zext i8 %0 to i32 ret i32 %conv } ;; A test with an extern global variable representing the table. @table = external global [32 x i8], align 1 define i32 @log2_32_5(i32 %v) { ; CHECK-LABEL: @log2_32_5( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[SHR:%.*]] = lshr i32 [[V:%.*]], 1 ; CHECK-NEXT: [[OR:%.*]] = or i32 [[SHR]], [[V]] ; CHECK-NEXT: [[SHR1:%.*]] = lshr i32 [[OR]], 2 ; CHECK-NEXT: [[OR2:%.*]] = or i32 [[SHR1]], [[OR]] ; CHECK-NEXT: [[SHR3:%.*]] = lshr i32 [[OR2]], 4 ; CHECK-NEXT: [[OR4:%.*]] = or i32 [[SHR3]], [[OR2]] ; CHECK-NEXT: [[SHR5:%.*]] = lshr i32 [[OR4]], 8 ; CHECK-NEXT: [[OR6:%.*]] = or i32 [[SHR5]], [[OR4]] ; CHECK-NEXT: [[SHR7:%.*]] = lshr i32 [[OR6]], 15 ; CHECK-NEXT: [[OR8:%.*]] = or i32 [[SHR7]], [[OR6]] ; CHECK-NEXT: [[MUL:%.*]] = mul i32 [[OR8]], 130329821 ; CHECK-NEXT: [[SHR9:%.*]] = lshr i32 [[MUL]], 26 ; CHECK-NEXT: [[IDXPROM:%.*]] = zext nneg i32 [[SHR9]] to i64 ; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [32 x i8], ptr @table, i64 0, i64 [[IDXPROM]] ; CHECK-NEXT: [[TMP0:%.*]] = load i8, ptr [[ARRAYIDX]], align 1 ; CHECK-NEXT: [[CONV:%.*]] = zext i8 [[TMP0]] to i32 ; CHECK-NEXT: ret i32 [[CONV]] ; entry: %shr = lshr i32 %v, 1 %or = or i32 %shr, %v %shr1 = lshr i32 %or, 2 %or2 = or i32 %shr1, %or %shr3 = lshr i32 %or2, 4 %or4 = or i32 %shr3, %or2 %shr5 = lshr i32 %or4, 8 %or6 = or i32 %shr5, %or4 %shr7 = lshr i32 %or6, 15 %or8 = or i32 %shr7, %or6 %mul = mul i32 %or8, 130329821 %shr9 = lshr i32 %mul, 26 %idxprom = zext nneg i32 %shr9 to i64 %arrayidx = getelementptr inbounds [32 x i8], ptr @table, i64 0, i64 %idxprom %0 = load i8, ptr %arrayidx, align 1 %conv = zext i8 %0 to i32 ret i32 %conv } ;; We want only constant tables to be considered as LOG2 ones. @log2_3.table = global [32 x i8] c"\00\09\01\0A\0D\15\02\1D\0B\0E\10\12\16\19\03\1E\08\0C\14\1C\0F\11\18\07\13\1B\17\06\1A\05\04\1F", align 1 ;; These are some negative tests with a wrong instruction sequences. define i32 @log2_32_6(i32 %v) { ; CHECK-LABEL: @log2_32_6( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[SHR:%.*]] = lshr i32 [[V:%.*]], 1 ; CHECK-NEXT: [[OR:%.*]] = or i32 [[SHR]], [[V]] ; CHECK-NEXT: [[SHR1:%.*]] = lshr i32 [[OR]], 2 ; CHECK-NEXT: [[OR2:%.*]] = or i32 [[SHR1]], [[OR]] ; CHECK-NEXT: [[SHR3:%.*]] = lshr i32 [[OR2]], 4 ; CHECK-NEXT: [[OR4:%.*]] = or i32 [[SHR3]], [[OR2]] ; CHECK-NEXT: [[SHR5:%.*]] = lshr i32 [[OR4]], 8 ; CHECK-NEXT: [[OR6:%.*]] = or i32 [[SHR5]], [[OR4]] ; CHECK-NEXT: [[SHR7:%.*]] = lshr i32 [[OR6]], 15 ; CHECK-NEXT: [[OR8:%.*]] = or i32 [[SHR7]], [[OR6]] ; CHECK-NEXT: [[MUL:%.*]] = mul i32 [[OR8]], 130329821 ; CHECK-NEXT: [[SHR9:%.*]] = lshr i32 [[MUL]], 27 ; CHECK-NEXT: [[IDXPROM:%.*]] = zext nneg i32 [[SHR9]] to i64 ; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [32 x i8], ptr @log2_3.table, i64 0, i64 [[IDXPROM]] ; CHECK-NEXT: [[TMP0:%.*]] = load i8, ptr [[ARRAYIDX]], align 1 ; CHECK-NEXT: [[CONV:%.*]] = zext i8 [[TMP0]] to i32 ; CHECK-NEXT: ret i32 [[CONV]] ; entry: %shr = lshr i32 %v, 1 %or = or i32 %shr, %v %shr1 = lshr i32 %or, 2 %or2 = or i32 %shr1, %or %shr3 = lshr i32 %or2, 4 %or4 = or i32 %shr3, %or2 %shr5 = lshr i32 %or4, 8 %or6 = or i32 %shr5, %or4 %shr7 = lshr i32 %or6, 15 %or8 = or i32 %shr7, %or6 %mul = mul i32 %or8, 130329821 %shr9 = lshr i32 %mul, 27 %idxprom = zext nneg i32 %shr9 to i64 %arrayidx = getelementptr inbounds [32 x i8], ptr @log2_3.table, i64 0, i64 %idxprom %0 = load i8, ptr %arrayidx, align 1 %conv = zext i8 %0 to i32 ret i32 %conv }