1; RUN: opt < %s -instcombine -S | FileCheck %s 2 3; Make sure all library calls are eliminated when the input is known positive. 4 5declare float @fabsf(float) 6declare double @fabs(double) 7declare fp128 @fabsl(fp128) 8declare float @llvm.fma.f32(float, float, float) 9declare float @llvm.fmuladd.f32(float, float, float) 10 11define float @square_fabs_call_f32(float %x) { 12 %mul = fmul float %x, %x 13 %fabsf = tail call float @fabsf(float %mul) 14 ret float %fabsf 15 16; CHECK-LABEL: square_fabs_call_f32( 17; CHECK-NEXT: %mul = fmul float %x, %x 18; CHECK-NEXT: %fabsf = tail call float @fabsf(float %mul) 19; CHECK-NEXT: ret float %fabsf 20} 21 22define double @square_fabs_call_f64(double %x) { 23 %mul = fmul double %x, %x 24 %fabs = tail call double @fabs(double %mul) 25 ret double %fabs 26 27; CHECK-LABEL: square_fabs_call_f64( 28; CHECK-NEXT: %mul = fmul double %x, %x 29; CHECK-NEXT: %fabs = tail call double @fabs(double %mul) 30; CHECK-NEXT: ret double %fabs 31} 32 33define fp128 @square_fabs_call_f128(fp128 %x) { 34 %mul = fmul fp128 %x, %x 35 %fabsl = tail call fp128 @fabsl(fp128 %mul) 36 ret fp128 %fabsl 37 38; CHECK-LABEL: square_fabs_call_f128( 39; CHECK-NEXT: %mul = fmul fp128 %x, %x 40; CHECK-NEXT: %fabsl = tail call fp128 @fabsl(fp128 %mul) 41; CHECK-NEXT: ret fp128 %fabsl 42} 43 44; Make sure all intrinsic calls are eliminated when the input is known 45; positive. 46 47declare float @llvm.fabs.f32(float) 48declare double @llvm.fabs.f64(double) 49declare fp128 @llvm.fabs.f128(fp128) 50 51; The fabs cannot be eliminated because %x may be a NaN 52define float @square_fabs_intrinsic_f32(float %x) { 53 %mul = fmul float %x, %x 54 %fabsf = tail call float @llvm.fabs.f32(float %mul) 55 ret float %fabsf 56 57; CHECK-LABEL: square_fabs_intrinsic_f32( 58; CHECK-NEXT: %mul = fmul float %x, %x 59; CHECK-NEXT: %fabsf = tail call float @llvm.fabs.f32(float %mul) 60; CHECK-NEXT: ret float %fabsf 61} 62 63define double @square_fabs_intrinsic_f64(double %x) { 64 %mul = fmul double %x, %x 65 %fabs = tail call double @llvm.fabs.f64(double %mul) 66 ret double %fabs 67 68; CHECK-LABEL: square_fabs_intrinsic_f64( 69; CHECK-NEXT: %mul = fmul double %x, %x 70; CHECK-NEXT: %fabs = tail call double @llvm.fabs.f64(double %mul) 71; CHECK-NEXT: ret double %fabs 72} 73 74define fp128 @square_fabs_intrinsic_f128(fp128 %x) { 75 %mul = fmul fp128 %x, %x 76 %fabsl = tail call fp128 @llvm.fabs.f128(fp128 %mul) 77 ret fp128 %fabsl 78 79; CHECK-LABEL: square_fabs_intrinsic_f128( 80; CHECK-NEXT: %mul = fmul fp128 %x, %x 81; CHECK-NEXT: %fabsl = tail call fp128 @llvm.fabs.f128(fp128 %mul) 82; CHECK-NEXT: ret fp128 %fabsl 83} 84 85define float @square_nnan_fabs_intrinsic_f32(float %x) { 86 %mul = fmul nnan float %x, %x 87 %fabsf = call float @llvm.fabs.f32(float %mul) 88 ret float %fabsf 89 90; CHECK-LABEL: square_nnan_fabs_intrinsic_f32( 91; CHECK-NEXT: %mul = fmul nnan float %x, %x 92; CHECK-NEXT: ret float %mul 93} 94 95; Shrinking a library call to a smaller type should not be inhibited by nor inhibit the square optimization. 96 97define float @square_fabs_shrink_call1(float %x) { 98 %ext = fpext float %x to double 99 %sq = fmul double %ext, %ext 100 %fabs = call double @fabs(double %sq) 101 %trunc = fptrunc double %fabs to float 102 ret float %trunc 103 104; CHECK-LABEL: square_fabs_shrink_call1( 105; CHECK-NEXT: %ext = fpext float %x to double 106; CHECK-NEXT: %sq = fmul double %ext, %ext 107; CHECK-NEXT: call double @fabs(double %sq) 108; CHECK-NEXT: %trunc = fptrunc double %fabs to float 109; CHECK-NEXT: ret float %trunc 110} 111 112define float @square_fabs_shrink_call2(float %x) { 113 %sq = fmul float %x, %x 114 %ext = fpext float %sq to double 115 %fabs = call double @fabs(double %ext) 116 %trunc = fptrunc double %fabs to float 117 ret float %trunc 118 119; CHECK-LABEL: square_fabs_shrink_call2( 120; CHECK-NEXT: %sq = fmul float %x, %x 121; CHECK-NEXT: %fabsf = call float @fabsf(float %sq) 122; CHECK-NEXT: ret float %fabsf 123} 124 125; CHECK-LABEL: @fabs_select_constant_negative_positive( 126; CHECK: %fabs = select i1 %cmp, float 1.000000e+00, float 2.000000e+00 127; CHECK-NEXT: ret float %fabs 128define float @fabs_select_constant_negative_positive(i32 %c) { 129 %cmp = icmp eq i32 %c, 0 130 %select = select i1 %cmp, float -1.0, float 2.0 131 %fabs = call float @llvm.fabs.f32(float %select) 132 ret float %fabs 133} 134 135; CHECK-LABEL: @fabs_select_constant_positive_negative( 136; CHECK: %fabs = select i1 %cmp, float 1.000000e+00, float 2.000000e+00 137; CHECK-NEXT: ret float %fabs 138define float @fabs_select_constant_positive_negative(i32 %c) { 139 %cmp = icmp eq i32 %c, 0 140 %select = select i1 %cmp, float 1.0, float -2.0 141 %fabs = call float @llvm.fabs.f32(float %select) 142 ret float %fabs 143} 144 145; CHECK-LABEL: @fabs_select_constant_negative_negative( 146; CHECK: %fabs = select i1 %cmp, float 1.000000e+00, float 2.000000e+00 147; CHECK-NEXT: ret float %fabs 148define float @fabs_select_constant_negative_negative(i32 %c) { 149 %cmp = icmp eq i32 %c, 0 150 %select = select i1 %cmp, float -1.0, float -2.0 151 %fabs = call float @llvm.fabs.f32(float %select) 152 ret float %fabs 153} 154 155; CHECK-LABEL: @fabs_select_constant_neg0( 156; CHECK-NEXT: ret float 0.0 157define float @fabs_select_constant_neg0(i32 %c) { 158 %cmp = icmp eq i32 %c, 0 159 %select = select i1 %cmp, float -0.0, float 0.0 160 %fabs = call float @llvm.fabs.f32(float %select) 161 ret float %fabs 162} 163 164; CHECK-LABEL: @fabs_select_var_constant_negative( 165; CHECK: %select = select i1 %cmp, float %x, float -1.000000e+00 166; CHECK: %fabs = call float @llvm.fabs.f32(float %select) 167define float @fabs_select_var_constant_negative(i32 %c, float %x) { 168 %cmp = icmp eq i32 %c, 0 169 %select = select i1 %cmp, float %x, float -1.0 170 %fabs = call float @llvm.fabs.f32(float %select) 171 ret float %fabs 172} 173 174; The fabs cannot be eliminated because %x may be a NaN 175define float @square_fma_fabs_intrinsic_f32(float %x) { 176 %fma = call float @llvm.fma.f32(float %x, float %x, float 1.0) 177 %fabsf = call float @llvm.fabs.f32(float %fma) 178 ret float %fabsf 179 180; CHECK-LABEL: @square_fma_fabs_intrinsic_f32( 181; CHECK-NEXT: %fma = call float @llvm.fma.f32(float %x, float %x, float 1.000000e+00) 182; CHECK-NEXT: %fabsf = call float @llvm.fabs.f32(float %fma) 183; CHECK-NEXT: ret float %fabsf 184} 185 186; The fabs cannot be eliminated because %x may be a NaN 187define float @square_nnan_fma_fabs_intrinsic_f32(float %x) { 188 %fma = call nnan float @llvm.fma.f32(float %x, float %x, float 1.0) 189 %fabsf = call float @llvm.fabs.f32(float %fma) 190 ret float %fabsf 191 192; CHECK-LABEL: @square_nnan_fma_fabs_intrinsic_f32( 193; CHECK-NEXT: %fma = call nnan float @llvm.fma.f32(float %x, float %x, float 1.000000e+00) 194; CHECK-NEXT: ret float %fma 195} 196 197define float @square_fmuladd_fabs_intrinsic_f32(float %x) { 198 %fmuladd = call float @llvm.fmuladd.f32(float %x, float %x, float 1.0) 199 %fabsf = call float @llvm.fabs.f32(float %fmuladd) 200 ret float %fabsf 201 202; CHECK-LABEL: @square_fmuladd_fabs_intrinsic_f32( 203; CHECK-NEXT: %fmuladd = call float @llvm.fmuladd.f32(float %x, float %x, float 1.000000e+00) 204; CHECK-NEXT: %fabsf = call float @llvm.fabs.f32(float %fmuladd) 205; CHECK-NEXT: ret float %fabsf 206} 207 208define float @square_nnan_fmuladd_fabs_intrinsic_f32(float %x) { 209 %fmuladd = call nnan float @llvm.fmuladd.f32(float %x, float %x, float 1.0) 210 %fabsf = call float @llvm.fabs.f32(float %fmuladd) 211 ret float %fabsf 212 213; CHECK-LABEL: @square_nnan_fmuladd_fabs_intrinsic_f32( 214; CHECK-NEXT: %fmuladd = call nnan float @llvm.fmuladd.f32(float %x, float %x, float 1.000000e+00) 215; CHECK-NEXT: ret float %fmuladd 216} 217