1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt < %s -passes=instcombine -S | FileCheck %s 3 4define float @fadd_fpext_op0(float %x, double %y) { 5; CHECK-LABEL: @fadd_fpext_op0( 6; CHECK-NEXT: [[EXT:%.*]] = fpext float [[X:%.*]] to double 7; CHECK-NEXT: [[BO:%.*]] = fadd reassoc double [[Y:%.*]], [[EXT]] 8; CHECK-NEXT: [[R:%.*]] = fptrunc double [[BO]] to float 9; CHECK-NEXT: ret float [[R]] 10; 11 %ext = fpext float %x to double 12 %bo = fadd reassoc double %ext, %y 13 %r = fptrunc double %bo to float 14 ret float %r 15} 16 17define half @fsub_fpext_op1(half %x, double %y) { 18; CHECK-LABEL: @fsub_fpext_op1( 19; CHECK-NEXT: [[EXT:%.*]] = fpext half [[X:%.*]] to double 20; CHECK-NEXT: [[BO:%.*]] = fsub reassoc double [[Y:%.*]], [[EXT]] 21; CHECK-NEXT: [[R:%.*]] = fptrunc double [[BO]] to half 22; CHECK-NEXT: ret half [[R]] 23; 24 %ext = fpext half %x to double 25 %bo = fsub reassoc double %y, %ext 26 %r = fptrunc double %bo to half 27 ret half %r 28} 29 30define <2 x float> @fdiv_constant_op0(<2 x double> %x) { 31; CHECK-LABEL: @fdiv_constant_op0( 32; CHECK-NEXT: [[BO:%.*]] = fdiv reassoc <2 x double> <double 4.210000e+01, double -1.000000e-01>, [[X:%.*]] 33; CHECK-NEXT: [[R:%.*]] = fptrunc <2 x double> [[BO]] to <2 x float> 34; CHECK-NEXT: ret <2 x float> [[R]] 35; 36 %bo = fdiv reassoc <2 x double> <double 42.1, double -0.1>, %x 37 %r = fptrunc <2 x double> %bo to <2 x float> 38 ret <2 x float> %r 39} 40 41define <2 x half> @fmul_constant_op1(<2 x float> %x) { 42; CHECK-LABEL: @fmul_constant_op1( 43; CHECK-NEXT: [[BO:%.*]] = fmul reassoc <2 x float> [[X:%.*]], <float 0x47EFFFFFE0000000, float 5.000000e-01> 44; CHECK-NEXT: [[R:%.*]] = fptrunc <2 x float> [[BO]] to <2 x half> 45; CHECK-NEXT: ret <2 x half> [[R]] 46; 47 %bo = fmul reassoc <2 x float> %x, <float 0x47efffffe0000000, float 0.5> 48 %r = fptrunc <2 x float> %bo to <2 x half> 49 ret <2 x half> %r 50} 51 52define float @fptrunc_select_true_val(float %x, double %y, i1 %cond) { 53; CHECK-LABEL: @fptrunc_select_true_val( 54; CHECK-NEXT: [[TMP1:%.*]] = fptrunc double [[Y:%.*]] to float 55; CHECK-NEXT: [[NARROW_SEL:%.*]] = select i1 [[COND:%.*]], float [[TMP1]], float [[X:%.*]] 56; CHECK-NEXT: ret float [[NARROW_SEL]] 57; 58 %e = fpext float %x to double 59 %sel = select fast i1 %cond, double %y, double %e 60 %r = fptrunc double %sel to float 61 ret float %r 62} 63 64define float @fptrunc_fast_select_true_val(float %x, double %y, i1 %cond) { 65; CHECK-LABEL: @fptrunc_fast_select_true_val( 66; CHECK-NEXT: [[TMP1:%.*]] = fptrunc fast double [[Y:%.*]] to float 67; CHECK-NEXT: [[NARROW_SEL:%.*]] = select i1 [[COND:%.*]], float [[TMP1]], float [[X:%.*]] 68; CHECK-NEXT: ret float [[NARROW_SEL]] 69; 70 %e = fpext float %x to double 71 %sel = select fast i1 %cond, double %y, double %e 72 %r = fptrunc fast double %sel to float 73 ret float %r 74} 75 76define <2 x float> @fptrunc_select_false_val(<2 x float> %x, <2 x double> %y, <2 x i1> %cond) { 77; CHECK-LABEL: @fptrunc_select_false_val( 78; CHECK-NEXT: [[TMP1:%.*]] = fptrunc <2 x double> [[Y:%.*]] to <2 x float> 79; CHECK-NEXT: [[NARROW_SEL:%.*]] = select <2 x i1> [[COND:%.*]], <2 x float> [[X:%.*]], <2 x float> [[TMP1]] 80; CHECK-NEXT: ret <2 x float> [[NARROW_SEL]] 81; 82 %e = fpext <2 x float> %x to <2 x double> 83 %sel = select nnan <2 x i1> %cond, <2 x double> %e, <2 x double> %y 84 %r = fptrunc <2 x double> %sel to <2 x float> 85 ret <2 x float> %r 86} 87 88define <2 x float> @fptrunc_nnan_select_false_val(<2 x float> %x, <2 x double> %y, <2 x i1> %cond) { 89; CHECK-LABEL: @fptrunc_nnan_select_false_val( 90; CHECK-NEXT: [[TMP1:%.*]] = fptrunc nnan <2 x double> [[Y:%.*]] to <2 x float> 91; CHECK-NEXT: [[NARROW_SEL:%.*]] = select <2 x i1> [[COND:%.*]], <2 x float> [[X:%.*]], <2 x float> [[TMP1]] 92; CHECK-NEXT: ret <2 x float> [[NARROW_SEL]] 93; 94 %e = fpext <2 x float> %x to <2 x double> 95 %sel = select nnan <2 x i1> %cond, <2 x double> %e, <2 x double> %y 96 %r = fptrunc nnan <2 x double> %sel to <2 x float> 97 ret <2 x float> %r 98} 99 100declare void @use(float) 101 102define half @fptrunc_select_true_val_extra_use(half %x, float %y, i1 %cond) { 103; CHECK-LABEL: @fptrunc_select_true_val_extra_use( 104; CHECK-NEXT: [[E:%.*]] = fpext half [[X:%.*]] to float 105; CHECK-NEXT: call void @use(float [[E]]) 106; CHECK-NEXT: [[TMP1:%.*]] = fptrunc float [[Y:%.*]] to half 107; CHECK-NEXT: [[NARROW_SEL:%.*]] = select i1 [[COND:%.*]], half [[TMP1]], half [[X]] 108; CHECK-NEXT: ret half [[NARROW_SEL]] 109; 110 %e = fpext half %x to float 111 call void @use(float %e) 112 %sel = select ninf i1 %cond, float %y, float %e 113 %r = fptrunc float %sel to half 114 ret half %r 115} 116 117define half @fptrunc_max(half %arg) { 118; CHECK-LABEL: @fptrunc_max( 119; CHECK-NEXT: [[CMP:%.*]] = fcmp olt half [[ARG:%.*]], 0xH0000 120; CHECK-NEXT: [[NARROW_SEL:%.*]] = select i1 [[CMP]], half 0xH0000, half [[ARG]] 121; CHECK-NEXT: ret half [[NARROW_SEL]] 122; 123 %ext = fpext half %arg to double 124 %cmp = fcmp olt double %ext, 0.000000e+00 125 %max = select i1 %cmp, double 0.000000e+00, double %ext 126 %trunc = fptrunc double %max to half 127 ret half %trunc 128} 129 130; Negative test - this would require an extra instruction. 131 132define half @fptrunc_select_true_val_extra_use_2(half %x, float %y, i1 %cond) { 133; CHECK-LABEL: @fptrunc_select_true_val_extra_use_2( 134; CHECK-NEXT: [[E:%.*]] = fpext half [[X:%.*]] to float 135; CHECK-NEXT: [[SEL:%.*]] = select ninf i1 [[COND:%.*]], float [[Y:%.*]], float [[E]] 136; CHECK-NEXT: call void @use(float [[SEL]]) 137; CHECK-NEXT: [[R:%.*]] = fptrunc float [[SEL]] to half 138; CHECK-NEXT: ret half [[R]] 139; 140 %e = fpext half %x to float 141 %sel = select ninf i1 %cond, float %y, float %e 142 call void @use(float %sel) 143 %r = fptrunc float %sel to half 144 ret half %r 145} 146 147; Negative test - the extend must be from the same source type as the result of the trunc. 148 149define float @fptrunc_select_true_val_type_mismatch(half %x, double %y, i1 %cond) { 150; CHECK-LABEL: @fptrunc_select_true_val_type_mismatch( 151; CHECK-NEXT: [[E:%.*]] = fpext half [[X:%.*]] to double 152; CHECK-NEXT: [[SEL:%.*]] = select i1 [[COND:%.*]], double [[Y:%.*]], double [[E]] 153; CHECK-NEXT: [[R:%.*]] = fptrunc double [[SEL]] to float 154; CHECK-NEXT: ret float [[R]] 155; 156 %e = fpext half %x to double 157 %sel = select i1 %cond, double %y, double %e 158 %r = fptrunc double %sel to float 159 ret float %r 160} 161 162; Negative test - but given enough FMF, should this be folded? 163 164define float @fptrunc_select_true_val_type_mismatch_fast(half %x, double %y, i1 %cond) { 165; CHECK-LABEL: @fptrunc_select_true_val_type_mismatch_fast( 166; CHECK-NEXT: [[E:%.*]] = fpext half [[X:%.*]] to double 167; CHECK-NEXT: [[SEL:%.*]] = select fast i1 [[COND:%.*]], double [[Y:%.*]], double [[E]] 168; CHECK-NEXT: [[R:%.*]] = fptrunc double [[SEL]] to float 169; CHECK-NEXT: ret float [[R]] 170; 171 %e = fpext half %x to double 172 %sel = select fast i1 %cond, double %y, double %e 173 %r = fptrunc double %sel to float 174 ret float %r 175} 176 177; Convert from integer is exact, so convert directly to float. 178 179define <2 x float> @ItoFtoF_s54_f64_f32(<2 x i54> %i) { 180; CHECK-LABEL: @ItoFtoF_s54_f64_f32( 181; CHECK-NEXT: [[R:%.*]] = sitofp <2 x i54> [[I:%.*]] to <2 x float> 182; CHECK-NEXT: ret <2 x float> [[R]] 183; 184 %x = sitofp <2 x i54> %i to <2 x double> 185 %r = fptrunc <2 x double> %x to <2 x float> 186 ret <2 x float> %r 187} 188 189; Convert from integer is exact, so convert directly to half. 190; Extra use is ok. 191 192define half @ItoFtoF_u24_f32_f16(i24 %i) { 193; CHECK-LABEL: @ItoFtoF_u24_f32_f16( 194; CHECK-NEXT: [[X:%.*]] = uitofp i24 [[I:%.*]] to float 195; CHECK-NEXT: call void @use(float [[X]]) 196; CHECK-NEXT: [[R:%.*]] = uitofp i24 [[I]] to half 197; CHECK-NEXT: ret half [[R]] 198; 199 %x = uitofp i24 %i to float 200 call void @use(float %x) 201 %r = fptrunc float %x to half 202 ret half %r 203} 204 205; Negative test - intermediate rounding in float type. 206 207define float @ItoFtoF_s55_f64_f32(i55 %i) { 208; CHECK-LABEL: @ItoFtoF_s55_f64_f32( 209; CHECK-NEXT: [[X:%.*]] = sitofp i55 [[I:%.*]] to double 210; CHECK-NEXT: [[R:%.*]] = fptrunc double [[X]] to float 211; CHECK-NEXT: ret float [[R]] 212; 213 %x = sitofp i55 %i to double 214 %r = fptrunc double %x to float 215 ret float %r 216} 217 218; Negative test - intermediate rounding in float type. 219 220define half @ItoFtoF_u25_f32_f16(i25 %i) { 221; CHECK-LABEL: @ItoFtoF_u25_f32_f16( 222; CHECK-NEXT: [[X:%.*]] = uitofp i25 [[I:%.*]] to float 223; CHECK-NEXT: [[R:%.*]] = fptrunc float [[X]] to half 224; CHECK-NEXT: ret half [[R]] 225; 226 %x = uitofp i25 %i to float 227 %r = fptrunc float %x to half 228 ret half %r 229} 230 231; Negative test - bitcast bfloat to half is not optimized 232 233define half @fptrunc_to_bfloat_bitcast_to_half(float %src) { 234; CHECK-LABEL: @fptrunc_to_bfloat_bitcast_to_half( 235; CHECK-NEXT: [[TRUNC:%.*]] = fptrunc float [[SRC:%.*]] to bfloat 236; CHECK-NEXT: [[CAST:%.*]] = bitcast bfloat [[TRUNC]] to half 237; CHECK-NEXT: ret half [[CAST]] 238; 239 %trunc = fptrunc float %src to bfloat 240 %cast = bitcast bfloat %trunc to half 241 ret half %cast 242} 243