; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt -S -passes=instsimplify < %s | FileCheck %s declare <4 x i16> @llvm.abs.v4i16(<4 x i16>, i1 immarg) declare i32 @llvm.abs.i32(i32, i1 immarg) declare i64 @llvm.abs.i64(i64, i1 immarg) ; check (a == 0) ? 0 : abs(a) define i32 @select_i32_eq0_abs_f(i32 %a) { ; CHECK-LABEL: @select_i32_eq0_abs_f( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[ABS:%.*]] = tail call i32 @llvm.abs.i32(i32 [[A:%.*]], i1 false) ; CHECK-NEXT: ret i32 [[ABS]] ; entry: %cond = icmp eq i32 %a, 0 %abs = tail call i32 @llvm.abs.i32(i32 %a, i1 false) %res = select i1 %cond, i32 0, i32 %abs ret i32 %res } define i32 @select_i32_eq0_abs_t(i32 %a) { ; CHECK-LABEL: @select_i32_eq0_abs_t( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[ABS:%.*]] = tail call i32 @llvm.abs.i32(i32 [[A:%.*]], i1 true) ; CHECK-NEXT: ret i32 [[ABS]] ; entry: %cond = icmp eq i32 %a, 0 %abs = tail call i32 @llvm.abs.i32(i32 %a, i1 true) %res = select i1 %cond, i32 0, i32 %abs ret i32 %res } ; check (a == int_min) ? int_min : abs(a) define i32 @select_i32_eqINTMIN_abs_f(i32 %a) { ; CHECK-LABEL: @select_i32_eqINTMIN_abs_f( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[ABS:%.*]] = tail call i32 @llvm.abs.i32(i32 [[A:%.*]], i1 false) ; CHECK-NEXT: ret i32 [[ABS]] ; entry: %cond = icmp eq i32 %a, -2147483648 %abs = tail call i32 @llvm.abs.i32(i32 %a, i1 false) %res = select i1 %cond, i32 -2147483648, i32 %abs ret i32 %res } ; should not transform define i32 @select_i32_eqINTMIN_abs_t(i32 %a) { ; CHECK-LABEL: @select_i32_eqINTMIN_abs_t( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 [[A:%.*]], -2147483648 ; CHECK-NEXT: [[ABS:%.*]] = tail call i32 @llvm.abs.i32(i32 [[A]], i1 true) ; CHECK-NEXT: [[RES:%.*]] = select i1 [[COND]], i32 -2147483648, i32 [[ABS]] ; CHECK-NEXT: ret i32 [[RES]] ; entry: %cond = icmp eq i32 %a, -2147483648 %abs = tail call i32 @llvm.abs.i32(i32 %a, i1 true) %res = select i1 %cond, i32 -2147483648, i32 %abs ret i32 %res } ; check random values, like (a == -255) ? 255 : abs(a) define i32 @select_i32_eqneg255_abs_f(i32 %a) { ; CHECK-LABEL: @select_i32_eqneg255_abs_f( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[ABS:%.*]] = tail call i32 @llvm.abs.i32(i32 [[A:%.*]], i1 false) ; CHECK-NEXT: ret i32 [[ABS]] ; entry: %cond = icmp eq i32 %a, -255 %abs = tail call i32 @llvm.abs.i32(i32 %a, i1 false) %res = select i1 %cond, i32 255, i32 %abs ret i32 %res } define i32 @select_i32_eqneg255_abs_t(i32 %a) { ; CHECK-LABEL: @select_i32_eqneg255_abs_t( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[ABS:%.*]] = tail call i32 @llvm.abs.i32(i32 [[A:%.*]], i1 true) ; CHECK-NEXT: ret i32 [[ABS]] ; entry: %cond = icmp eq i32 %a, -255 %abs = tail call i32 @llvm.abs.i32(i32 %a, i1 true) %res = select i1 %cond, i32 255, i32 %abs ret i32 %res } define i32 @select_i32_eq65555_abs_f(i32 %a) { ; CHECK-LABEL: @select_i32_eq65555_abs_f( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[ABS:%.*]] = tail call i32 @llvm.abs.i32(i32 [[A:%.*]], i1 false) ; CHECK-NEXT: ret i32 [[ABS]] ; entry: %cond = icmp eq i32 %a, 65555 %abs = tail call i32 @llvm.abs.i32(i32 %a, i1 false) %res = select i1 %cond, i32 65555, i32 %abs ret i32 %res } define i32 @select_i32_eq65555_abs_t(i32 %a) { ; CHECK-LABEL: @select_i32_eq65555_abs_t( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[ABS:%.*]] = tail call i32 @llvm.abs.i32(i32 [[A:%.*]], i1 true) ; CHECK-NEXT: ret i32 [[ABS]] ; entry: %cond = icmp eq i32 %a, 65555 %abs = tail call i32 @llvm.abs.i32(i32 %a, i1 true) %res = select i1 %cond, i32 65555, i32 %abs ret i32 %res } ; check random values, but the transform doesn't make sense, e.g. ; (a == 255) ? -255 : abs(a) define i32 @bad_select_i32_eq255_abs_f(i32 %a) { ; CHECK-LABEL: @bad_select_i32_eq255_abs_f( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 [[A:%.*]], 255 ; CHECK-NEXT: [[ABS:%.*]] = tail call i32 @llvm.abs.i32(i32 [[A]], i1 false) ; CHECK-NEXT: [[RES:%.*]] = select i1 [[COND]], i32 -255, i32 [[ABS]] ; CHECK-NEXT: ret i32 [[RES]] ; entry: %cond = icmp eq i32 %a, 255 %abs = tail call i32 @llvm.abs.i32(i32 %a, i1 false) %res = select i1 %cond, i32 -255, i32 %abs ret i32 %res } define i32 @bad_select_i32_eq255_abs_t(i32 %a) { ; CHECK-LABEL: @bad_select_i32_eq255_abs_t( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 [[A:%.*]], 255 ; CHECK-NEXT: [[ABS:%.*]] = tail call i32 @llvm.abs.i32(i32 [[A]], i1 true) ; CHECK-NEXT: [[RES:%.*]] = select i1 [[COND]], i32 -255, i32 [[ABS]] ; CHECK-NEXT: ret i32 [[RES]] ; entry: %cond = icmp eq i32 %a, 255 %abs = tail call i32 @llvm.abs.i32(i32 %a, i1 true) %res = select i1 %cond, i32 -255, i32 %abs ret i32 %res } define i32 @bad_select_i32_eq65555_abs_f(i32 %a) { ; CHECK-LABEL: @bad_select_i32_eq65555_abs_f( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 [[A:%.*]], -65555 ; CHECK-NEXT: [[ABS:%.*]] = tail call i32 @llvm.abs.i32(i32 [[A]], i1 false) ; CHECK-NEXT: [[RES:%.*]] = select i1 [[COND]], i32 65554, i32 [[ABS]] ; CHECK-NEXT: ret i32 [[RES]] ; entry: %cond = icmp eq i32 %a, -65555 %abs = tail call i32 @llvm.abs.i32(i32 %a, i1 false) %res = select i1 %cond, i32 65554, i32 %abs ret i32 %res } define i32 @bad_select_i32_eq65555_abs_t(i32 %a) { ; CHECK-LABEL: @bad_select_i32_eq65555_abs_t( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 [[A:%.*]], -65555 ; CHECK-NEXT: [[ABS:%.*]] = tail call i32 @llvm.abs.i32(i32 [[A]], i1 true) ; CHECK-NEXT: [[RES:%.*]] = select i1 [[COND]], i32 65554, i32 [[ABS]] ; CHECK-NEXT: ret i32 [[RES]] ; entry: %cond = icmp eq i32 %a, -65555 %abs = tail call i32 @llvm.abs.i32(i32 %a, i1 true) %res = select i1 %cond, i32 65554, i32 %abs ret i32 %res } define i32 @select_i32_ne0_abs_f(i32 %a) { ; CHECK-LABEL: @select_i32_ne0_abs_f( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[ABS:%.*]] = tail call i32 @llvm.abs.i32(i32 [[A:%.*]], i1 false) ; CHECK-NEXT: ret i32 [[ABS]] ; entry: %cond = icmp ne i32 %a, 0 %abs = tail call i32 @llvm.abs.i32(i32 %a, i1 false) %res = select i1 %cond, i32 %abs, i32 0 ret i32 %res } define i32 @select_i32_ne0_abs_t(i32 %a) { ; CHECK-LABEL: @select_i32_ne0_abs_t( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[ABS:%.*]] = tail call i32 @llvm.abs.i32(i32 [[A:%.*]], i1 true) ; CHECK-NEXT: ret i32 [[ABS]] ; entry: %cond = icmp ne i32 %a, 0 %abs = tail call i32 @llvm.abs.i32(i32 %a, i1 true) %res = select i1 %cond, i32 %abs, i32 0 ret i32 %res } define i64 @select_i64_eq0_abs_t(i64 %a) { ; CHECK-LABEL: @select_i64_eq0_abs_t( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[ABS:%.*]] = tail call i64 @llvm.abs.i64(i64 [[A:%.*]], i1 true) ; CHECK-NEXT: ret i64 [[ABS]] ; entry: %cond = icmp eq i64 %a, 0 %abs = tail call i64 @llvm.abs.i64(i64 %a, i1 true) %res = select i1 %cond, i64 0, i64 %abs ret i64 %res } define i64 @select_i64_ne0_abs_t(i64 %a) { ; CHECK-LABEL: @select_i64_ne0_abs_t( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[ABS:%.*]] = tail call i64 @llvm.abs.i64(i64 [[A:%.*]], i1 true) ; CHECK-NEXT: ret i64 [[ABS]] ; entry: %cond = icmp ne i64 %a, 0 %abs = tail call i64 @llvm.abs.i64(i64 %a, i1 true) %res = select i1 %cond, i64 %abs, i64 0 ret i64 %res } ; TODO: Handle vector cases? define <4 x i16> @select_v4i16_eq0_abs_t(<4 x i16> %a) { ; CHECK-LABEL: @select_v4i16_eq0_abs_t( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[COND:%.*]] = icmp eq <4 x i16> [[A:%.*]], zeroinitializer ; CHECK-NEXT: [[ABS:%.*]] = tail call <4 x i16> @llvm.abs.v4i16(<4 x i16> [[A]], i1 true) ; CHECK-NEXT: [[RES:%.*]] = select <4 x i1> [[COND]], <4 x i16> zeroinitializer, <4 x i16> [[ABS]] ; CHECK-NEXT: ret <4 x i16> [[RES]] ; entry: %cond = icmp eq <4 x i16> %a, %abs = tail call <4 x i16> @llvm.abs.v4i16(<4 x i16> %a, i1 true) %res = select <4 x i1> %cond, <4 x i16> , <4 x i16> %abs ret <4 x i16> %res } define <4 x i16> @select_v4i16_ne0_abs_t(<4 x i16> %a) { ; CHECK-LABEL: @select_v4i16_ne0_abs_t( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[COND:%.*]] = icmp ne <4 x i16> [[A:%.*]], zeroinitializer ; CHECK-NEXT: [[ABS:%.*]] = tail call <4 x i16> @llvm.abs.v4i16(<4 x i16> [[A]], i1 true) ; CHECK-NEXT: [[RES:%.*]] = select <4 x i1> [[COND]], <4 x i16> [[ABS]], <4 x i16> zeroinitializer ; CHECK-NEXT: ret <4 x i16> [[RES]] ; entry: %cond = icmp ne <4 x i16> %a, %abs = tail call <4 x i16> @llvm.abs.v4i16(<4 x i16> %a, i1 true) %res = select <4 x i1> %cond, <4 x i16> %abs, <4 x i16> ret <4 x i16> %res } define <4 x i16> @select_v4i16_ne0_abs_t_with_undef(<4 x i16> %a) { ; CHECK-LABEL: @select_v4i16_ne0_abs_t_with_undef( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[COND:%.*]] = icmp ne <4 x i16> [[A:%.*]], zeroinitializer ; CHECK-NEXT: [[ABS:%.*]] = tail call <4 x i16> @llvm.abs.v4i16(<4 x i16> [[A]], i1 true) ; CHECK-NEXT: [[RES:%.*]] = select <4 x i1> [[COND]], <4 x i16> [[ABS]], <4 x i16> ; CHECK-NEXT: ret <4 x i16> [[RES]] ; entry: %cond = icmp ne <4 x i16> %a, %abs = tail call <4 x i16> @llvm.abs.v4i16(<4 x i16> %a, i1 true) %res = select <4 x i1> %cond, <4 x i16> %abs, <4 x i16> ret <4 x i16> %res } define i32 @bad_select_i32_ne0_abs(i32 %a) { ; CHECK-LABEL: @bad_select_i32_ne0_abs( ; CHECK-NEXT: entry: ; CHECK-NEXT: ret i32 0 ; entry: %cond = icmp ne i32 %a, 0 %abs = tail call i32 @llvm.abs.i32(i32 %a, i1 false) %res = select i1 %cond, i32 0, i32 %abs ret i32 %res } define i32 @bad_select_i32_eq0_abs(i32 %a) { ; CHECK-LABEL: @bad_select_i32_eq0_abs( ; CHECK-NEXT: entry: ; CHECK-NEXT: ret i32 0 ; entry: %cond = icmp eq i32 %a, 0 %abs = tail call i32 @llvm.abs.i32(i32 %a, i1 false) %res = select i1 %cond, i32 %abs, i32 0 ret i32 %res } define <4 x i16> @badsplat1_select_v4i16_ne0_abs(<4 x i16> %a) { ; CHECK-LABEL: @badsplat1_select_v4i16_ne0_abs( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[COND:%.*]] = icmp ne <4 x i16> [[A:%.*]], ; CHECK-NEXT: [[ABS:%.*]] = tail call <4 x i16> @llvm.abs.v4i16(<4 x i16> [[A]], i1 true) ; CHECK-NEXT: [[RES:%.*]] = select <4 x i1> [[COND]], <4 x i16> [[ABS]], <4 x i16> ; CHECK-NEXT: ret <4 x i16> [[RES]] ; entry: %cond = icmp ne <4 x i16> %a, %abs = tail call <4 x i16> @llvm.abs.v4i16(<4 x i16> %a, i1 true) %res = select <4 x i1> %cond, <4 x i16> %abs, <4 x i16> ret <4 x i16> %res } define <4 x i16> @badsplat2_select_v4i16_ne0_abs(<4 x i16> %a) { ; CHECK-LABEL: @badsplat2_select_v4i16_ne0_abs( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[COND:%.*]] = icmp ne <4 x i16> [[A:%.*]], ; CHECK-NEXT: [[ABS:%.*]] = tail call <4 x i16> @llvm.abs.v4i16(<4 x i16> [[A]], i1 true) ; CHECK-NEXT: [[RES:%.*]] = select <4 x i1> [[COND]], <4 x i16> [[ABS]], <4 x i16> ; CHECK-NEXT: ret <4 x i16> [[RES]] ; entry: %cond = icmp ne <4 x i16> %a, %abs = tail call <4 x i16> @llvm.abs.v4i16(<4 x i16> %a, i1 true) %res = select <4 x i1> %cond, <4 x i16> %abs, <4 x i16> ret <4 x i16> %res } define <4 x i16> @badsplat3_select_v4i16_ne0_abs(<4 x i16> %a) { ; CHECK-LABEL: @badsplat3_select_v4i16_ne0_abs( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[COND:%.*]] = icmp ne <4 x i16> [[A:%.*]], zeroinitializer ; CHECK-NEXT: [[ABS:%.*]] = tail call <4 x i16> @llvm.abs.v4i16(<4 x i16> [[A]], i1 true) ; CHECK-NEXT: [[RES:%.*]] = select <4 x i1> [[COND]], <4 x i16> [[ABS]], <4 x i16> ; CHECK-NEXT: ret <4 x i16> [[RES]] ; entry: %cond = icmp ne <4 x i16> %a, %abs = tail call <4 x i16> @llvm.abs.v4i16(<4 x i16> %a, i1 true) %res = select <4 x i1> %cond, <4 x i16> %abs, <4 x i16> ret <4 x i16> %res }