
We previously handled ConstantExpr scalable splats in 5d929794a87602cfd873381e11cc99149196bb49, but only fpexts. ConstantExpr fpexts have since been removed, and simultaneously we didn't handle splats of constants that weren't extended. This updates it to remove the fpext check and instead see if we can shrink the result of getSplatValue. Note that the test case doesn't get completely folded away due to #132922
462 lines
14 KiB
LLVM
462 lines
14 KiB
LLVM
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
|
; RUN: opt < %s -passes=instcombine -S | FileCheck %s
|
|
|
|
define float @test(float %x) nounwind {
|
|
; CHECK-LABEL: @test(
|
|
; CHECK-NEXT: [[T34:%.*]] = fadd float [[X:%.*]], 0.000000e+00
|
|
; CHECK-NEXT: ret float [[T34]]
|
|
;
|
|
%t1 = fpext float %x to double
|
|
%t3 = fadd double %t1, 0.000000e+00
|
|
%t34 = fptrunc double %t3 to float
|
|
ret float %t34
|
|
}
|
|
|
|
define float @test2(float %x, float %y) nounwind {
|
|
; CHECK-LABEL: @test2(
|
|
; CHECK-NEXT: [[T56:%.*]] = fmul float [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: ret float [[T56]]
|
|
;
|
|
%t1 = fpext float %x to double
|
|
%t23 = fpext float %y to double
|
|
%t5 = fmul double %t1, %t23
|
|
%t56 = fptrunc double %t5 to float
|
|
ret float %t56
|
|
}
|
|
|
|
define float @test3(float %x, float %y) nounwind {
|
|
; CHECK-LABEL: @test3(
|
|
; CHECK-NEXT: [[T56:%.*]] = fdiv float [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: ret float [[T56]]
|
|
;
|
|
%t1 = fpext float %x to double
|
|
%t23 = fpext float %y to double
|
|
%t5 = fdiv double %t1, %t23
|
|
%t56 = fptrunc double %t5 to float
|
|
ret float %t56
|
|
}
|
|
|
|
define float @test4(float %x) nounwind {
|
|
; CHECK-LABEL: @test4(
|
|
; CHECK-NEXT: [[T34:%.*]] = fneg float [[X:%.*]]
|
|
; CHECK-NEXT: ret float [[T34]]
|
|
;
|
|
%t1 = fpext float %x to double
|
|
%t2 = fsub double -0.000000e+00, %t1
|
|
%t34 = fptrunc double %t2 to float
|
|
ret float %t34
|
|
}
|
|
|
|
define float @test4_unary_fneg(float %x) nounwind {
|
|
; CHECK-LABEL: @test4_unary_fneg(
|
|
; CHECK-NEXT: [[T34:%.*]] = fneg float [[X:%.*]]
|
|
; CHECK-NEXT: ret float [[T34]]
|
|
;
|
|
%t1 = fpext float %x to double
|
|
%t2 = fneg double %t1
|
|
%t34 = fptrunc double %t2 to float
|
|
ret float %t34
|
|
}
|
|
|
|
; Test with vector splat constant
|
|
define <2 x float> @test5(<2 x float> %x) nounwind {
|
|
; CHECK-LABEL: @test5(
|
|
; CHECK-NEXT: [[T34:%.*]] = fadd <2 x float> [[X:%.*]], zeroinitializer
|
|
; CHECK-NEXT: ret <2 x float> [[T34]]
|
|
;
|
|
%t1 = fpext <2 x float> %x to <2 x double>
|
|
%t3 = fadd <2 x double> %t1, <double 0.000000e+00, double 0.000000e+00>
|
|
%t34 = fptrunc <2 x double> %t3 to <2 x float>
|
|
ret <2 x float> %t34
|
|
}
|
|
|
|
; Test with a non-splat constant
|
|
define <2 x float> @test6(<2 x float> %x) nounwind {
|
|
; CHECK-LABEL: @test6(
|
|
; CHECK-NEXT: [[T34:%.*]] = fadd <2 x float> [[X:%.*]], <float 0.000000e+00, float -0.000000e+00>
|
|
; CHECK-NEXT: ret <2 x float> [[T34]]
|
|
;
|
|
%t1 = fpext <2 x float> %x to <2 x double>
|
|
%t3 = fadd <2 x double> %t1, <double 0.000000e+00, double -0.000000e+00>
|
|
%t34 = fptrunc <2 x double> %t3 to <2 x float>
|
|
ret <2 x float> %t34
|
|
}
|
|
|
|
; Test with an undef element
|
|
define <2 x float> @test6_undef(<2 x float> %x) nounwind {
|
|
; CHECK-LABEL: @test6_undef(
|
|
; CHECK-NEXT: [[T34:%.*]] = fadd <2 x float> [[X:%.*]], <float 0.000000e+00, float undef>
|
|
; CHECK-NEXT: ret <2 x float> [[T34]]
|
|
;
|
|
%t1 = fpext <2 x float> %x to <2 x double>
|
|
%t3 = fadd <2 x double> %t1, <double 0.000000e+00, double undef>
|
|
%t34 = fptrunc <2 x double> %t3 to <2 x float>
|
|
ret <2 x float> %t34
|
|
}
|
|
|
|
define <2 x float> @not_half_shrinkable(<2 x float> %x) {
|
|
; CHECK-LABEL: @not_half_shrinkable(
|
|
; CHECK-NEXT: [[R:%.*]] = fadd <2 x float> [[X:%.*]], <float 0.000000e+00, float 2.049000e+03>
|
|
; CHECK-NEXT: ret <2 x float> [[R]]
|
|
;
|
|
%ext = fpext <2 x float> %x to <2 x double>
|
|
%add = fadd <2 x double> %ext, <double 0.0, double 2049.0>
|
|
%r = fptrunc <2 x double> %add to <2 x float>
|
|
ret <2 x float> %r
|
|
}
|
|
|
|
define half @test7(float %a) nounwind {
|
|
; CHECK-LABEL: @test7(
|
|
; CHECK-NEXT: [[Z:%.*]] = fptrunc float [[A:%.*]] to half
|
|
; CHECK-NEXT: ret half [[Z]]
|
|
;
|
|
%y = fpext float %a to double
|
|
%z = fptrunc double %y to half
|
|
ret half %z
|
|
}
|
|
|
|
define float @test8(half %a) nounwind {
|
|
; CHECK-LABEL: @test8(
|
|
; CHECK-NEXT: [[Z:%.*]] = fpext half [[A:%.*]] to float
|
|
; CHECK-NEXT: ret float [[Z]]
|
|
;
|
|
%y = fpext half %a to double
|
|
%z = fptrunc double %y to float
|
|
ret float %z
|
|
}
|
|
|
|
define float @test9(half %x, half %y) nounwind {
|
|
; CHECK-LABEL: @test9(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = fpext half [[X:%.*]] to float
|
|
; CHECK-NEXT: [[TMP2:%.*]] = fpext half [[Y:%.*]] to float
|
|
; CHECK-NEXT: [[T56:%.*]] = fmul float [[TMP1]], [[TMP2]]
|
|
; CHECK-NEXT: ret float [[T56]]
|
|
;
|
|
%t1 = fpext half %x to double
|
|
%t23 = fpext half %y to double
|
|
%t5 = fmul double %t1, %t23
|
|
%t56 = fptrunc double %t5 to float
|
|
ret float %t56
|
|
}
|
|
|
|
define float @test10(half %x, float %y) nounwind {
|
|
; CHECK-LABEL: @test10(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = fpext half [[X:%.*]] to float
|
|
; CHECK-NEXT: [[T56:%.*]] = fmul float [[Y:%.*]], [[TMP1]]
|
|
; CHECK-NEXT: ret float [[T56]]
|
|
;
|
|
%t1 = fpext half %x to double
|
|
%t23 = fpext float %y to double
|
|
%t5 = fmul double %t1, %t23
|
|
%t56 = fptrunc double %t5 to float
|
|
ret float %t56
|
|
}
|
|
|
|
define float @test11(half %x) nounwind {
|
|
; CHECK-LABEL: @test11(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = fpext half [[X:%.*]] to float
|
|
; CHECK-NEXT: [[T34:%.*]] = fadd float [[TMP1]], 0.000000e+00
|
|
; CHECK-NEXT: ret float [[T34]]
|
|
;
|
|
%t1 = fpext half %x to double
|
|
%t3 = fadd double %t1, 0.000000e+00
|
|
%t34 = fptrunc double %t3 to float
|
|
ret float %t34
|
|
}
|
|
|
|
define float @test12(float %x, half %y) nounwind {
|
|
; CHECK-LABEL: @test12(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = fpext half [[Y:%.*]] to float
|
|
; CHECK-NEXT: [[T34:%.*]] = fadd float [[X:%.*]], [[TMP1]]
|
|
; CHECK-NEXT: ret float [[T34]]
|
|
;
|
|
%t1 = fpext float %x to double
|
|
%t2 = fpext half %y to double
|
|
%t3 = fadd double %t1, %t2
|
|
%t34 = fptrunc double %t3 to float
|
|
ret float %t34
|
|
}
|
|
|
|
define float @test13(half %x, float %y) nounwind {
|
|
; CHECK-LABEL: @test13(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = fpext half [[X:%.*]] to float
|
|
; CHECK-NEXT: [[T56:%.*]] = fdiv float [[TMP1]], [[Y:%.*]]
|
|
; CHECK-NEXT: ret float [[T56]]
|
|
;
|
|
%t1 = fpext half %x to double
|
|
%t23 = fpext float %y to double
|
|
%t5 = fdiv double %t1, %t23
|
|
%t56 = fptrunc double %t5 to float
|
|
ret float %t56
|
|
}
|
|
|
|
define float @test14(float %x, half %y) nounwind {
|
|
; CHECK-LABEL: @test14(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = fpext half [[Y:%.*]] to float
|
|
; CHECK-NEXT: [[T56:%.*]] = fdiv float [[X:%.*]], [[TMP1]]
|
|
; CHECK-NEXT: ret float [[T56]]
|
|
;
|
|
%t1 = fpext float %x to double
|
|
%t23 = fpext half %y to double
|
|
%t5 = fdiv double %t1, %t23
|
|
%t56 = fptrunc double %t5 to float
|
|
ret float %t56
|
|
}
|
|
|
|
define float @test15(half %x, half %y) nounwind {
|
|
; CHECK-LABEL: @test15(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = fpext half [[X:%.*]] to float
|
|
; CHECK-NEXT: [[TMP2:%.*]] = fpext half [[Y:%.*]] to float
|
|
; CHECK-NEXT: [[T56:%.*]] = fdiv float [[TMP1]], [[TMP2]]
|
|
; CHECK-NEXT: ret float [[T56]]
|
|
;
|
|
%t1 = fpext half %x to double
|
|
%t23 = fpext half %y to double
|
|
%t5 = fdiv double %t1, %t23
|
|
%t56 = fptrunc double %t5 to float
|
|
ret float %t56
|
|
}
|
|
|
|
define float @test16(half %x, float %y) nounwind {
|
|
; CHECK-LABEL: @test16(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = fpext half [[X:%.*]] to float
|
|
; CHECK-NEXT: [[TMP2:%.*]] = frem float [[TMP1]], [[Y:%.*]]
|
|
; CHECK-NEXT: ret float [[TMP2]]
|
|
;
|
|
%t1 = fpext half %x to double
|
|
%t23 = fpext float %y to double
|
|
%t5 = frem double %t1, %t23
|
|
%t56 = fptrunc double %t5 to float
|
|
ret float %t56
|
|
}
|
|
|
|
define float @test17(float %x, half %y) nounwind {
|
|
; CHECK-LABEL: @test17(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = fpext half [[Y:%.*]] to float
|
|
; CHECK-NEXT: [[TMP2:%.*]] = frem float [[X:%.*]], [[TMP1]]
|
|
; CHECK-NEXT: ret float [[TMP2]]
|
|
;
|
|
%t1 = fpext float %x to double
|
|
%t23 = fpext half %y to double
|
|
%t5 = frem double %t1, %t23
|
|
%t56 = fptrunc double %t5 to float
|
|
ret float %t56
|
|
}
|
|
|
|
define float @test18(half %x, half %y) nounwind {
|
|
; CHECK-LABEL: @test18(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = frem half [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: [[T56:%.*]] = fpext half [[TMP1]] to float
|
|
; CHECK-NEXT: ret float [[T56]]
|
|
;
|
|
%t1 = fpext half %x to double
|
|
%t23 = fpext half %y to double
|
|
%t5 = frem double %t1, %t23
|
|
%t56 = fptrunc double %t5 to float
|
|
ret float %t56
|
|
}
|
|
|
|
; Convert from integer is exact, so convert directly to double.
|
|
|
|
define double @ItoFtoF_s25_f32_f64(i25 %i) {
|
|
; CHECK-LABEL: @ItoFtoF_s25_f32_f64(
|
|
; CHECK-NEXT: [[R:%.*]] = sitofp i25 [[I:%.*]] to double
|
|
; CHECK-NEXT: ret double [[R]]
|
|
;
|
|
%x = sitofp i25 %i to float
|
|
%r = fpext float %x to double
|
|
ret double %r
|
|
}
|
|
|
|
; Convert from integer is exact, so convert directly to fp128.
|
|
|
|
define fp128 @ItoFtoF_u24_f32_f128(i24 %i) {
|
|
; CHECK-LABEL: @ItoFtoF_u24_f32_f128(
|
|
; CHECK-NEXT: [[R:%.*]] = uitofp i24 [[I:%.*]] to fp128
|
|
; CHECK-NEXT: ret fp128 [[R]]
|
|
;
|
|
%x = uitofp i24 %i to float
|
|
%r = fpext float %x to fp128
|
|
ret fp128 %r
|
|
}
|
|
|
|
; Negative test - intermediate rounding in float type.
|
|
|
|
define double @ItoFtoF_s26_f32_f64(i26 %i) {
|
|
; CHECK-LABEL: @ItoFtoF_s26_f32_f64(
|
|
; CHECK-NEXT: [[X:%.*]] = sitofp i26 [[I:%.*]] to float
|
|
; CHECK-NEXT: [[R:%.*]] = fpext float [[X]] to double
|
|
; CHECK-NEXT: ret double [[R]]
|
|
;
|
|
%x = sitofp i26 %i to float
|
|
%r = fpext float %x to double
|
|
ret double %r
|
|
}
|
|
|
|
; Negative test - intermediate rounding in float type.
|
|
|
|
define double @ItoFtoF_u25_f32_f64(i25 %i) {
|
|
; CHECK-LABEL: @ItoFtoF_u25_f32_f64(
|
|
; CHECK-NEXT: [[X:%.*]] = uitofp i25 [[I:%.*]] to float
|
|
; CHECK-NEXT: [[R:%.*]] = fpext float [[X]] to double
|
|
; CHECK-NEXT: ret double [[R]]
|
|
;
|
|
%x = uitofp i25 %i to float
|
|
%r = fpext float %x to double
|
|
ret double %r
|
|
}
|
|
|
|
; UB on overflow guarantees that the input is small enough to fit in i32.
|
|
|
|
define double @FtoItoFtoF_f32_s32_f32_f64(float %f) {
|
|
; CHECK-LABEL: @FtoItoFtoF_f32_s32_f32_f64(
|
|
; CHECK-NEXT: [[I:%.*]] = fptosi float [[F:%.*]] to i32
|
|
; CHECK-NEXT: [[R:%.*]] = sitofp i32 [[I]] to double
|
|
; CHECK-NEXT: ret double [[R]]
|
|
;
|
|
%i = fptosi float %f to i32
|
|
%x = sitofp i32 %i to float
|
|
%r = fpext float %x to double
|
|
ret double %r
|
|
}
|
|
|
|
declare void @use_i32(i32)
|
|
declare void @use_f32(float)
|
|
|
|
; Extra uses are ok; unsigned is ok.
|
|
|
|
define double @FtoItoFtoF_f32_u32_f32_f64_extra_uses(float %f) {
|
|
; CHECK-LABEL: @FtoItoFtoF_f32_u32_f32_f64_extra_uses(
|
|
; CHECK-NEXT: [[I:%.*]] = fptoui float [[F:%.*]] to i32
|
|
; CHECK-NEXT: call void @use_i32(i32 [[I]])
|
|
; CHECK-NEXT: [[X:%.*]] = uitofp i32 [[I]] to float
|
|
; CHECK-NEXT: call void @use_f32(float [[X]])
|
|
; CHECK-NEXT: [[R:%.*]] = uitofp i32 [[I]] to double
|
|
; CHECK-NEXT: ret double [[R]]
|
|
;
|
|
%i = fptoui float %f to i32
|
|
call void @use_i32(i32 %i)
|
|
%x = uitofp i32 %i to float
|
|
call void @use_f32(float %x)
|
|
%r = fpext float %x to double
|
|
ret double %r
|
|
}
|
|
|
|
; Vectors are ok; initial type can be smaller than intermediate type.
|
|
|
|
define <3 x double> @FtoItoFtoF_v3f16_v3s32_v3f32_v3f64(<3 x half> %f) {
|
|
; CHECK-LABEL: @FtoItoFtoF_v3f16_v3s32_v3f32_v3f64(
|
|
; CHECK-NEXT: [[I:%.*]] = fptosi <3 x half> [[F:%.*]] to <3 x i32>
|
|
; CHECK-NEXT: [[R:%.*]] = sitofp <3 x i32> [[I]] to <3 x double>
|
|
; CHECK-NEXT: ret <3 x double> [[R]]
|
|
;
|
|
%i = fptosi <3 x half> %f to <3 x i32>
|
|
%x = sitofp <3 x i32> %i to <3 x float>
|
|
%r = fpext <3 x float> %x to <3 x double>
|
|
ret <3 x double> %r
|
|
}
|
|
|
|
; Wider than double is ok.
|
|
|
|
define fp128 @FtoItoFtoF_f32_s64_f64_f128(float %f) {
|
|
; CHECK-LABEL: @FtoItoFtoF_f32_s64_f64_f128(
|
|
; CHECK-NEXT: [[I:%.*]] = fptosi float [[F:%.*]] to i64
|
|
; CHECK-NEXT: [[R:%.*]] = sitofp i64 [[I]] to fp128
|
|
; CHECK-NEXT: ret fp128 [[R]]
|
|
;
|
|
%i = fptosi float %f to i64
|
|
%x = sitofp i64 %i to double
|
|
%r = fpext double %x to fp128
|
|
ret fp128 %r
|
|
}
|
|
|
|
; Target-specific type is ok.
|
|
|
|
define x86_fp80 @FtoItoFtoF_f64_u54_f64_f80(double %f) {
|
|
; CHECK-LABEL: @FtoItoFtoF_f64_u54_f64_f80(
|
|
; CHECK-NEXT: [[I:%.*]] = fptoui double [[F:%.*]] to i54
|
|
; CHECK-NEXT: [[R:%.*]] = uitofp i54 [[I]] to x86_fp80
|
|
; CHECK-NEXT: ret x86_fp80 [[R]]
|
|
;
|
|
%i = fptoui double %f to i54
|
|
%x = uitofp i54 %i to double
|
|
%r = fpext double %x to x86_fp80
|
|
ret x86_fp80 %r
|
|
}
|
|
|
|
; Weird target-specific type is ok (not possible to extend *from* that type).
|
|
|
|
define ppc_fp128 @FtoItoFtoF_f64_u54_f64_p128(double %f) {
|
|
; CHECK-LABEL: @FtoItoFtoF_f64_u54_f64_p128(
|
|
; CHECK-NEXT: [[I:%.*]] = fptoui double [[F:%.*]] to i54
|
|
; CHECK-NEXT: [[R:%.*]] = uitofp i54 [[I]] to ppc_fp128
|
|
; CHECK-NEXT: ret ppc_fp128 [[R]]
|
|
;
|
|
%i = fptoui double %f to i54
|
|
%x = uitofp i54 %i to double
|
|
%r = fpext double %x to ppc_fp128
|
|
ret ppc_fp128 %r
|
|
}
|
|
|
|
; Unsigned to signed is ok because signed int has smaller magnitude.
|
|
|
|
define double @FtoItoFtoF_f32_us32_f32_f64(float %f) {
|
|
; CHECK-LABEL: @FtoItoFtoF_f32_us32_f32_f64(
|
|
; CHECK-NEXT: [[I:%.*]] = fptoui float [[F:%.*]] to i32
|
|
; CHECK-NEXT: [[R:%.*]] = sitofp i32 [[I]] to double
|
|
; CHECK-NEXT: ret double [[R]]
|
|
;
|
|
%i = fptoui float %f to i32
|
|
%x = sitofp i32 %i to float
|
|
%r = fpext float %x to double
|
|
ret double %r
|
|
}
|
|
|
|
; Negative test: consider -1.0
|
|
|
|
define double @FtoItoFtoF_f32_su32_f32_f64(float %f) {
|
|
; CHECK-LABEL: @FtoItoFtoF_f32_su32_f32_f64(
|
|
; CHECK-NEXT: [[I:%.*]] = fptosi float [[F:%.*]] to i32
|
|
; CHECK-NEXT: [[X:%.*]] = uitofp i32 [[I]] to float
|
|
; CHECK-NEXT: [[R:%.*]] = fpext float [[X]] to double
|
|
; CHECK-NEXT: ret double [[R]]
|
|
;
|
|
%i = fptosi float %f to i32
|
|
%x = uitofp i32 %i to float
|
|
%r = fpext float %x to double
|
|
ret double %r
|
|
}
|
|
|
|
define half @bf16_to_f32_to_f16(bfloat %a) nounwind {
|
|
; CHECK-LABEL: @bf16_to_f32_to_f16(
|
|
; CHECK-NEXT: [[Y:%.*]] = fpext bfloat [[A:%.*]] to float
|
|
; CHECK-NEXT: [[Z:%.*]] = fptrunc float [[Y]] to half
|
|
; CHECK-NEXT: ret half [[Z]]
|
|
;
|
|
%y = fpext bfloat %a to float
|
|
%z = fptrunc float %y to half
|
|
ret half %z
|
|
}
|
|
|
|
define bfloat @bf16_frem(bfloat %x) {
|
|
; CHECK-LABEL: @bf16_frem(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = frem bfloat [[X:%.*]], 0xR40C9
|
|
; CHECK-NEXT: ret bfloat [[TMP1]]
|
|
;
|
|
%t1 = fpext bfloat %x to float
|
|
%t2 = frem float %t1, 6.281250e+00
|
|
%t3 = fptrunc float %t2 to bfloat
|
|
ret bfloat %t3
|
|
}
|
|
|
|
define <4 x float> @v4f32_fadd(<4 x float> %a) {
|
|
; CHECK-LABEL: @v4f32_fadd(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = fadd <4 x float> [[A:%.*]], splat (float -1.000000e+00)
|
|
; CHECK-NEXT: ret <4 x float> [[TMP1]]
|
|
;
|
|
%2 = fpext <4 x float> %a to <4 x double>
|
|
%4 = fadd <4 x double> %2, splat (double -1.000000e+00)
|
|
%5 = fptrunc <4 x double> %4 to <4 x float>
|
|
ret <4 x float> %5
|
|
}
|