| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 |
| |
| ; RUN: opt -S -passes=instcombine < %s | FileCheck %s |
| |
| ; When C0 is neither 0 nor 1: |
| ; umax(nuw_mul(x, C0), x + 1) is optimized to: |
| ; x == 0 ? 1 : nuw_mul(x, C0) |
| ; When C0 is not 0: |
| ; umax(nuw_shl(x, C0), x + 1) is optimized to: |
| ; x == 0 ? 1 : nuw_shl(x, C0) |
| |
| ; Positive Test Cases for `shl` |
| |
| define i64 @test_shl_by_2(i64 %x) { |
| ; CHECK-LABEL: define i64 @test_shl_by_2( |
| ; CHECK-SAME: i64 [[X:%.*]]) { |
| ; CHECK-NEXT: [[TMP2:%.*]] = shl nuw i64 [[X]], 2 |
| ; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i64 [[X]], 0 |
| ; CHECK-NEXT: [[MAX:%.*]] = select i1 [[TMP1]], i64 1, i64 [[TMP2]] |
| ; CHECK-NEXT: ret i64 [[MAX]] |
| ; |
| %x1 = add i64 %x, 1 |
| %shl = shl nuw i64 %x, 2 |
| %max = call i64 @llvm.umax.i64(i64 %shl, i64 %x1) |
| ret i64 %max |
| } |
| |
| define i64 @test_shl_by_5(i64 %x) { |
| ; CHECK-LABEL: define i64 @test_shl_by_5( |
| ; CHECK-SAME: i64 [[X:%.*]]) { |
| ; CHECK-NEXT: [[TMP2:%.*]] = shl nuw i64 [[X]], 5 |
| ; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i64 [[X]], 0 |
| ; CHECK-NEXT: [[MAX:%.*]] = select i1 [[TMP1]], i64 1, i64 [[TMP2]] |
| ; CHECK-NEXT: ret i64 [[MAX]] |
| ; |
| %x1 = add i64 %x, 1 |
| %shl = shl nuw i64 %x, 5 |
| %max = call i64 @llvm.umax.i64(i64 %shl, i64 %x1) |
| ret i64 %max |
| } |
| |
| define i64 @test_shl_with_nsw(i64 %x) { |
| ; CHECK-LABEL: define i64 @test_shl_with_nsw( |
| ; CHECK-SAME: i64 [[X:%.*]]) { |
| ; CHECK-NEXT: [[SHL:%.*]] = shl nuw nsw i64 [[X]], 2 |
| ; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i64 [[X]], 0 |
| ; CHECK-NEXT: [[MAX:%.*]] = select i1 [[TMP1]], i64 1, i64 [[SHL]] |
| ; CHECK-NEXT: ret i64 [[MAX]] |
| ; |
| %x1 = add i64 %x, 1 |
| %shl = shl nuw nsw i64 %x, 2 |
| %max = call i64 @llvm.umax.i64(i64 %shl, i64 %x1) |
| ret i64 %max |
| } |
| |
| define <2 x i64> @test_shl_vector_by_2(<2 x i64> %x) { |
| ; CHECK-LABEL: define <2 x i64> @test_shl_vector_by_2( |
| ; CHECK-SAME: <2 x i64> [[X:%.*]]) { |
| ; CHECK-NEXT: [[SHL:%.*]] = shl nuw <2 x i64> [[X]], splat (i64 2) |
| ; CHECK-NEXT: [[TMP1:%.*]] = icmp eq <2 x i64> [[X]], zeroinitializer |
| ; CHECK-NEXT: [[MAX:%.*]] = select <2 x i1> [[TMP1]], <2 x i64> splat (i64 1), <2 x i64> [[SHL]] |
| ; CHECK-NEXT: ret <2 x i64> [[MAX]] |
| ; |
| %x1 = add <2 x i64> %x, <i64 1, i64 1> |
| %shl = shl nuw <2 x i64> %x, <i64 2, i64 2> |
| %max = call <2 x i64> @llvm.umax.v2i64(<2 x i64> %shl, <2 x i64> %x1) |
| ret <2 x i64> %max |
| } |
| |
| ; Commuted Test Cases for `shl` |
| |
| define i64 @test_shl_umax_commuted(i64 %x) { |
| ; CHECK-LABEL: define i64 @test_shl_umax_commuted( |
| ; CHECK-SAME: i64 [[X:%.*]]) { |
| ; CHECK-NEXT: [[SHL:%.*]] = shl nuw i64 [[X]], 2 |
| ; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i64 [[X]], 0 |
| ; CHECK-NEXT: [[MAX:%.*]] = select i1 [[TMP1]], i64 1, i64 [[SHL]] |
| ; CHECK-NEXT: ret i64 [[MAX]] |
| ; |
| %x1 = add i64 %x, 1 |
| %shl = shl nuw i64 %x, 2 |
| %max = call i64 @llvm.umax.i64(i64 %x1, i64 %shl) |
| ret i64 %max |
| } |
| |
| ; Negative Test Cases for `shl` |
| |
| define i64 @test_shl_by_zero(i64 %x) { |
| ; CHECK-LABEL: define i64 @test_shl_by_zero( |
| ; CHECK-SAME: i64 [[X:%.*]]) { |
| ; CHECK-NEXT: [[X1:%.*]] = add i64 [[X]], 1 |
| ; CHECK-NEXT: [[MAX:%.*]] = call i64 @llvm.umax.i64(i64 [[X]], i64 [[X1]]) |
| ; CHECK-NEXT: ret i64 [[MAX]] |
| ; |
| %x1 = add i64 %x, 1 |
| %shl = shl nuw i64 %x, 0 |
| %max = call i64 @llvm.umax.i64(i64 %shl, i64 %x1) |
| ret i64 %max |
| } |
| |
| define i64 @test_shl_add_by_2(i64 %x) { |
| ; CHECK-LABEL: define i64 @test_shl_add_by_2( |
| ; CHECK-SAME: i64 [[X:%.*]]) { |
| ; CHECK-NEXT: [[X1:%.*]] = add i64 [[X]], 2 |
| ; CHECK-NEXT: [[SHL:%.*]] = shl nuw i64 [[X]], 2 |
| ; CHECK-NEXT: [[MAX:%.*]] = call i64 @llvm.umax.i64(i64 [[SHL]], i64 [[X1]]) |
| ; CHECK-NEXT: ret i64 [[MAX]] |
| ; |
| %x1 = add i64 %x, 2 |
| %shl = shl nuw i64 %x, 2 |
| %max = call i64 @llvm.umax.i64(i64 %shl, i64 %x1) |
| ret i64 %max |
| } |
| |
| define i64 @test_shl_without_nuw(i64 %x) { |
| ; CHECK-LABEL: define i64 @test_shl_without_nuw( |
| ; CHECK-SAME: i64 [[X:%.*]]) { |
| ; CHECK-NEXT: [[X1:%.*]] = add i64 [[X]], 1 |
| ; CHECK-NEXT: [[SHL:%.*]] = shl i64 [[X]], 2 |
| ; CHECK-NEXT: [[MAX:%.*]] = call i64 @llvm.umax.i64(i64 [[SHL]], i64 [[X1]]) |
| ; CHECK-NEXT: ret i64 [[MAX]] |
| ; |
| %x1 = add i64 %x, 1 |
| %shl = shl i64 %x, 2 |
| %max = call i64 @llvm.umax.i64(i64 %shl, i64 %x1) |
| ret i64 %max |
| } |
| |
| define i64 @test_shl_umin(i64 %x) { |
| ; CHECK-LABEL: define i64 @test_shl_umin( |
| ; CHECK-SAME: i64 [[X:%.*]]) { |
| ; CHECK-NEXT: [[X1:%.*]] = add i64 [[X]], 1 |
| ; CHECK-NEXT: [[SHL:%.*]] = shl nuw i64 [[X]], 2 |
| ; CHECK-NEXT: [[MAX:%.*]] = call i64 @llvm.umin.i64(i64 [[SHL]], i64 [[X1]]) |
| ; CHECK-NEXT: ret i64 [[MAX]] |
| ; |
| %x1 = add i64 %x, 1 |
| %shl = shl nuw i64 %x, 2 |
| %max = call i64 @llvm.umin.i64(i64 %shl, i64 %x1) |
| ret i64 %max |
| } |
| |
| ; Multi-use Test Cases for `shl` |
| declare void @use(i64) |
| |
| define i64 @test_shl_multi_use_add(i64 %x) { |
| ; CHECK-LABEL: define i64 @test_shl_multi_use_add( |
| ; CHECK-SAME: i64 [[X:%.*]]) { |
| ; CHECK-NEXT: [[X1:%.*]] = add i64 [[X]], 1 |
| ; CHECK-NEXT: call void @use(i64 [[X1]]) |
| ; CHECK-NEXT: [[TMP2:%.*]] = shl nuw i64 [[X]], 3 |
| ; CHECK-NEXT: [[MAX:%.*]] = call i64 @llvm.umax.i64(i64 [[TMP2]], i64 [[X1]]) |
| ; CHECK-NEXT: ret i64 [[MAX]] |
| ; |
| %x1 = add i64 %x, 1 |
| call void @use(i64 %x1) |
| %shl = shl nuw i64 %x, 3 |
| %max = call i64 @llvm.umax.i64(i64 %shl, i64 %x1) |
| ret i64 %max |
| } |
| |
| define i64 @test_shl_multi_use_shl(i64 %x) { |
| ; CHECK-LABEL: define i64 @test_shl_multi_use_shl( |
| ; CHECK-SAME: i64 [[X:%.*]]) { |
| ; CHECK-NEXT: [[SHL:%.*]] = shl nuw i64 [[X]], 2 |
| ; CHECK-NEXT: call void @use(i64 [[SHL]]) |
| ; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i64 [[X]], 0 |
| ; CHECK-NEXT: [[MAX:%.*]] = select i1 [[TMP1]], i64 1, i64 [[SHL]] |
| ; CHECK-NEXT: ret i64 [[MAX]] |
| ; |
| %x1 = add i64 %x, 1 |
| %shl = shl nuw i64 %x, 2 |
| call void @use(i64 %shl) |
| %max = call i64 @llvm.umax.i64(i64 %shl, i64 %x1) |
| ret i64 %max |
| } |
| |
| ; Positive Test Cases for `mul` |
| |
| define i64 @test_mul_by_3(i64 %x) { |
| ; CHECK-LABEL: define i64 @test_mul_by_3( |
| ; CHECK-SAME: i64 [[X:%.*]]) { |
| ; CHECK-NEXT: [[MUL:%.*]] = mul nuw i64 [[X]], 3 |
| ; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i64 [[X]], 0 |
| ; CHECK-NEXT: [[MAX:%.*]] = select i1 [[TMP1]], i64 1, i64 [[MUL]] |
| ; CHECK-NEXT: ret i64 [[MAX]] |
| ; |
| %x1 = add i64 %x, 1 |
| %mul = mul nuw i64 %x, 3 |
| %max = call i64 @llvm.umax.i64(i64 %mul, i64 %x1) |
| ret i64 %max |
| } |
| |
| define i64 @test_mul_by_5(i64 %x) { |
| ; CHECK-LABEL: define i64 @test_mul_by_5( |
| ; CHECK-SAME: i64 [[X:%.*]]) { |
| ; CHECK-NEXT: [[MUL:%.*]] = mul nuw i64 [[X]], 5 |
| ; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i64 [[X]], 0 |
| ; CHECK-NEXT: [[MAX:%.*]] = select i1 [[TMP1]], i64 1, i64 [[MUL]] |
| ; CHECK-NEXT: ret i64 [[MAX]] |
| ; |
| %x1 = add i64 %x, 1 |
| %mul = mul nuw i64 %x, 5 |
| %max = call i64 @llvm.umax.i64(i64 %mul, i64 %x1) |
| ret i64 %max |
| } |
| |
| define i64 @test_mul_with_nsw(i64 %x) { |
| ; CHECK-LABEL: define i64 @test_mul_with_nsw( |
| ; CHECK-SAME: i64 [[X:%.*]]) { |
| ; CHECK-NEXT: [[MUL:%.*]] = mul nuw nsw i64 [[X]], 3 |
| ; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i64 [[X]], 0 |
| ; CHECK-NEXT: [[MAX:%.*]] = select i1 [[TMP1]], i64 1, i64 [[MUL]] |
| ; CHECK-NEXT: ret i64 [[MAX]] |
| ; |
| %x1 = add i64 %x, 1 |
| %mul = mul nuw nsw i64 %x, 3 |
| %max = call i64 @llvm.umax.i64(i64 %mul, i64 %x1) |
| ret i64 %max |
| } |
| |
| define <2 x i64> @test_mul_vector_by_3(<2 x i64> %x) { |
| ; CHECK-LABEL: define <2 x i64> @test_mul_vector_by_3( |
| ; CHECK-SAME: <2 x i64> [[X:%.*]]) { |
| ; CHECK-NEXT: [[MUL:%.*]] = mul nuw <2 x i64> [[X]], splat (i64 3) |
| ; CHECK-NEXT: [[TMP1:%.*]] = icmp eq <2 x i64> [[X]], zeroinitializer |
| ; CHECK-NEXT: [[MAX:%.*]] = select <2 x i1> [[TMP1]], <2 x i64> splat (i64 1), <2 x i64> [[MUL]] |
| ; CHECK-NEXT: ret <2 x i64> [[MAX]] |
| ; |
| %x1 = add <2 x i64> %x, <i64 1, i64 1> |
| %mul = mul nuw <2 x i64> %x, <i64 3, i64 3> |
| %max = call <2 x i64> @llvm.umax.v2i64(<2 x i64> %mul, <2 x i64> %x1) |
| ret <2 x i64> %max |
| } |
| |
| ; Commuted Test Cases for `mul` |
| |
| define i64 @test_mul_max_commuted(i64 %x) { |
| ; CHECK-LABEL: define i64 @test_mul_max_commuted( |
| ; CHECK-SAME: i64 [[X:%.*]]) { |
| ; CHECK-NEXT: [[MUL:%.*]] = mul nuw i64 [[X]], 3 |
| ; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i64 [[X]], 0 |
| ; CHECK-NEXT: [[MAX:%.*]] = select i1 [[TMP1]], i64 1, i64 [[MUL]] |
| ; CHECK-NEXT: ret i64 [[MAX]] |
| ; |
| %x1 = add i64 %x, 1 |
| %mul = mul nuw i64 %x, 3 |
| %max = call i64 @llvm.umax.i64(i64 %x1, i64 %mul) |
| ret i64 %max |
| } |
| |
| ; Negative Test Cases for `mul` |
| |
| define i64 @test_mul_by_zero(i64 %x) { |
| ; CHECK-LABEL: define i64 @test_mul_by_zero( |
| ; CHECK-SAME: i64 [[X:%.*]]) { |
| ; CHECK-NEXT: [[X1:%.*]] = add i64 [[X]], 1 |
| ; CHECK-NEXT: ret i64 [[X1]] |
| ; |
| %x1 = add i64 %x, 1 |
| %mul = mul nuw i64 %x, 0 |
| %max = call i64 @llvm.umax.i64(i64 %mul, i64 %x1) |
| ret i64 %max |
| } |
| |
| define i64 @test_mul_by_1(i64 %x) { |
| ; CHECK-LABEL: define i64 @test_mul_by_1( |
| ; CHECK-SAME: i64 [[X:%.*]]) { |
| ; CHECK-NEXT: [[X1:%.*]] = add i64 [[X]], 1 |
| ; CHECK-NEXT: [[MAX:%.*]] = call i64 @llvm.umax.i64(i64 [[X]], i64 [[X1]]) |
| ; CHECK-NEXT: ret i64 [[MAX]] |
| ; |
| %x1 = add i64 %x, 1 |
| %mul = mul nuw i64 %x, 1 |
| %max = call i64 @llvm.umax.i64(i64 %mul, i64 %x1) |
| ret i64 %max |
| } |
| |
| define i64 @test_mul_add_by_2(i64 %x) { |
| ; CHECK-LABEL: define i64 @test_mul_add_by_2( |
| ; CHECK-SAME: i64 [[X:%.*]]) { |
| ; CHECK-NEXT: [[X1:%.*]] = add i64 [[X]], 2 |
| ; CHECK-NEXT: [[MUL:%.*]] = mul nuw i64 [[X]], 3 |
| ; CHECK-NEXT: [[MAX:%.*]] = call i64 @llvm.umax.i64(i64 [[MUL]], i64 [[X1]]) |
| ; CHECK-NEXT: ret i64 [[MAX]] |
| ; |
| %x1 = add i64 %x, 2 |
| %mul = mul nuw i64 %x, 3 |
| %max = call i64 @llvm.umax.i64(i64 %mul, i64 %x1) |
| ret i64 %max |
| } |
| |
| define i64 @test_mul_without_nuw(i64 %x) { |
| ; CHECK-LABEL: define i64 @test_mul_without_nuw( |
| ; CHECK-SAME: i64 [[X:%.*]]) { |
| ; CHECK-NEXT: [[X1:%.*]] = add i64 [[X]], 1 |
| ; CHECK-NEXT: [[MUL:%.*]] = mul i64 [[X]], 3 |
| ; CHECK-NEXT: [[MAX:%.*]] = call i64 @llvm.umax.i64(i64 [[MUL]], i64 [[X1]]) |
| ; CHECK-NEXT: ret i64 [[MAX]] |
| ; |
| %x1 = add i64 %x, 1 |
| %mul = mul i64 %x, 3 |
| %max = call i64 @llvm.umax.i64(i64 %mul, i64 %x1) |
| ret i64 %max |
| } |
| |
| define i64 @test_mul_umin(i64 %x) { |
| ; CHECK-LABEL: define i64 @test_mul_umin( |
| ; CHECK-SAME: i64 [[X:%.*]]) { |
| ; CHECK-NEXT: [[X1:%.*]] = add i64 [[X]], 1 |
| ; CHECK-NEXT: [[MUL:%.*]] = mul nuw i64 [[X]], 3 |
| ; CHECK-NEXT: [[MAX:%.*]] = call i64 @llvm.umin.i64(i64 [[MUL]], i64 [[X1]]) |
| ; CHECK-NEXT: ret i64 [[MAX]] |
| ; |
| %x1 = add i64 %x, 1 |
| %mul = mul nuw i64 %x, 3 |
| %max = call i64 @llvm.umin.i64(i64 %mul, i64 %x1) |
| ret i64 %max |
| } |
| |
| ; Multi-use Test Cases for `mul` |
| |
| define i64 @test_mul_multi_use_add(i64 %x) { |
| ; CHECK-LABEL: define i64 @test_mul_multi_use_add( |
| ; CHECK-SAME: i64 [[X:%.*]]) { |
| ; CHECK-NEXT: [[X1:%.*]] = add i64 [[X]], 1 |
| ; CHECK-NEXT: call void @use(i64 [[X1]]) |
| ; CHECK-NEXT: [[TMP2:%.*]] = mul nuw i64 [[X]], 3 |
| ; CHECK-NEXT: [[MAX:%.*]] = call i64 @llvm.umax.i64(i64 [[TMP2]], i64 [[X1]]) |
| ; CHECK-NEXT: ret i64 [[MAX]] |
| ; |
| %x1 = add i64 %x, 1 |
| call void @use(i64 %x1) |
| %mul = mul nuw i64 %x, 3 |
| %max = call i64 @llvm.umax.i64(i64 %mul, i64 %x1) |
| ret i64 %max |
| } |
| |
| define i64 @test_mul_multi_use_mul(i64 %x) { |
| ; CHECK-LABEL: define i64 @test_mul_multi_use_mul( |
| ; CHECK-SAME: i64 [[X:%.*]]) { |
| ; CHECK-NEXT: [[MUL:%.*]] = mul nuw i64 [[X]], 3 |
| ; CHECK-NEXT: call void @use(i64 [[MUL]]) |
| ; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i64 [[X]], 0 |
| ; CHECK-NEXT: [[MAX:%.*]] = select i1 [[TMP1]], i64 1, i64 [[MUL]] |
| ; CHECK-NEXT: ret i64 [[MAX]] |
| ; |
| %x1 = add i64 %x, 1 |
| %mul = mul nuw i64 %x, 3 |
| call void @use(i64 %mul) |
| %max = call i64 @llvm.umax.i64(i64 %mul, i64 %x1) |
| ret i64 %max |
| } |