| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6 | |
| ; RUN: opt -passes=ipsccp -S %s | FileCheck %s | |
| ; Folds that are only valid under the fast-math flags of the instruction being | |
| ; visited must take those flags into account, even if the other operand is | |
| ; overdefined. | |
| define float @fmul_zero_nnan_nsz(float %a) { | |
| ; CHECK-LABEL: define float @fmul_zero_nnan_nsz( | |
| ; CHECK-SAME: float [[A:%.*]]) { | |
| ; CHECK-NEXT: ret float 0.000000e+00 | |
| ; | |
| %r = fmul nnan nsz float %a, 0.000000e+00 | |
| ret float %r | |
| } | |
| define float @fmul_zero_nsz_only(float %a) { | |
| ; CHECK-LABEL: define float @fmul_zero_nsz_only( | |
| ; CHECK-SAME: float [[A:%.*]]) { | |
| ; CHECK-NEXT: [[R:%.*]] = fmul nsz float [[A]], 0.000000e+00 | |
| ; CHECK-NEXT: ret float [[R]] | |
| ; | |
| %r = fmul nsz float %a, 0.000000e+00 | |
| ret float %r | |
| } | |
| define float @fmul_zero_no_flags(float %a) { | |
| ; CHECK-LABEL: define float @fmul_zero_no_flags( | |
| ; CHECK-SAME: float [[A:%.*]]) { | |
| ; CHECK-NEXT: [[R:%.*]] = fmul float [[A]], 0.000000e+00 | |
| ; CHECK-NEXT: ret float [[R]] | |
| ; | |
| %r = fmul float %a, 0.000000e+00 | |
| ret float %r | |
| } | |
| define <2 x float> @fmul_zero_nnan_nsz_vec(<2 x float> %a) { | |
| ; CHECK-LABEL: define <2 x float> @fmul_zero_nnan_nsz_vec( | |
| ; CHECK-SAME: <2 x float> [[A:%.*]]) { | |
| ; CHECK-NEXT: ret <2 x float> zeroinitializer | |
| ; | |
| %r = fmul nnan nsz <2 x float> %a, zeroinitializer | |
| ret <2 x float> %r | |
| } | |
| define float @fdiv_zero_nnan_nsz(float %a) { | |
| ; CHECK-LABEL: define float @fdiv_zero_nnan_nsz( | |
| ; CHECK-SAME: float [[A:%.*]]) { | |
| ; CHECK-NEXT: ret float 0.000000e+00 | |
| ; | |
| %r = fdiv nnan nsz float 0.000000e+00, %a | |
| ret float %r | |
| } | |
| ; frem reaches simplifyFRemInst through the same overload. Mirrors the | |
| ; simplifyFRemInst coverage in InstSimplify/fast-math.ll, but with the folds | |
| ; driven by the solver's lattice rather than by simplifyInstruction. | |
| define double @frem_poszero_nnan(double %a) { | |
| ; CHECK-LABEL: define double @frem_poszero_nnan( | |
| ; CHECK-SAME: double [[A:%.*]]) { | |
| ; CHECK-NEXT: ret double 0.000000e+00 | |
| ; | |
| %r = frem nnan double 0.000000e+00, %a | |
| ret double %r | |
| } | |
| ; nsz is not necessary - the frem result always has the sign of the dividend. | |
| define double @frem_negzero_nnan(double %a) { | |
| ; CHECK-LABEL: define double @frem_negzero_nnan( | |
| ; CHECK-SAME: double [[A:%.*]]) { | |
| ; CHECK-NEXT: ret double -0.000000e+00 | |
| ; | |
| %r = frem nnan double -0.000000e+00, %a | |
| ret double %r | |
| } | |
| ; A poison element in the dividend still yields a full zero constant. | |
| define <2 x double> @frem_poszero_nnan_vec_poison(<2 x double> %a) { | |
| ; CHECK-LABEL: define <2 x double> @frem_poszero_nnan_vec_poison( | |
| ; CHECK-SAME: <2 x double> [[A:%.*]]) { | |
| ; CHECK-NEXT: ret <2 x double> zeroinitializer | |
| ; | |
| %r = frem nnan <2 x double> <double 0.000000e+00, double poison>, %a | |
| ret <2 x double> %r | |
| } | |
| define <2 x double> @frem_negzero_nnan_vec_poison(<2 x double> %a) { | |
| ; CHECK-LABEL: define <2 x double> @frem_negzero_nnan_vec_poison( | |
| ; CHECK-SAME: <2 x double> [[A:%.*]]) { | |
| ; CHECK-NEXT: ret <2 x double> splat (double -0.000000e+00) | |
| ; | |
| %r = frem nnan <2 x double> <double poison, double -0.000000e+00>, %a | |
| ret <2 x double> %r | |
| } | |
| ; 'ninf' alone does not enable the fold. | |
| define double @frem_poszero_ninf_only(double %a) { | |
| ; CHECK-LABEL: define double @frem_poszero_ninf_only( | |
| ; CHECK-SAME: double [[A:%.*]]) { | |
| ; CHECK-NEXT: [[R:%.*]] = frem ninf double 0.000000e+00, [[A]] | |
| ; CHECK-NEXT: ret double [[R]] | |
| ; | |
| %r = frem ninf double 0.000000e+00, %a | |
| ret double %r | |
| } | |
| define double @frem_poszero_no_flags(double %a) { | |
| ; CHECK-LABEL: define double @frem_poszero_no_flags( | |
| ; CHECK-SAME: double [[A:%.*]]) { | |
| ; CHECK-NEXT: [[R:%.*]] = frem double 0.000000e+00, [[A]] | |
| ; CHECK-NEXT: ret double [[R]] | |
| ; | |
| %r = frem double 0.000000e+00, %a | |
| ret double %r | |
| } | |
| ; The dividend is only known to be 0.0 after solving. | |
| define internal double @frem_callee(double %a, double %b) { | |
| ; CHECK-LABEL: define internal double @frem_callee( | |
| ; CHECK-SAME: double [[A:%.*]], double [[B:%.*]]) { | |
| ; CHECK-NEXT: ret double poison | |
| ; | |
| %r = frem nnan double %a, %b | |
| ret double %r | |
| } | |
| define double @frem_caller(double %x) { | |
| ; CHECK-LABEL: define double @frem_caller( | |
| ; CHECK-SAME: double [[X:%.*]]) { | |
| ; CHECK-NEXT: [[C:%.*]] = call double @frem_callee(double 0.000000e+00, double [[X]]) | |
| ; CHECK-NEXT: ret double 0.000000e+00 | |
| ; | |
| %c = call double @frem_callee(double 0.000000e+00, double %x) | |
| ret double %c | |
| } | |
| ; The constant operand is only known to be 0.0 after solving. | |
| define internal float @callee(float %a, float %b) { | |
| ; CHECK-LABEL: define internal float @callee( | |
| ; CHECK-SAME: float [[A:%.*]], float [[B:%.*]]) { | |
| ; CHECK-NEXT: ret float poison | |
| ; | |
| %r = fmul nnan nsz float %a, %b | |
| ret float %r | |
| } | |
| define float @caller(float %a) { | |
| ; CHECK-LABEL: define float @caller( | |
| ; CHECK-SAME: float [[A:%.*]]) { | |
| ; CHECK-NEXT: [[C:%.*]] = call float @callee(float [[A]], float 0.000000e+00) | |
| ; CHECK-NEXT: ret float 0.000000e+00 | |
| ; | |
| %c = call float @callee(float %a, float 0.000000e+00) | |
| ret float %c | |
| } | |
| ; %p is NaN when only the bb2 -> exit edge has been marked executable, which | |
| ; with 'nnan' makes %r poison. Once bb1 -> exit is executable as well, %p is | |
| ; overdefined and %r folds to 0.0. Make sure the lattice value for %r does not | |
| ; go from poison to a constant. | |
| define float @fmul_nan_then_overdefined(float %a, i1 %bc) { | |
| ; CHECK-LABEL: define float @fmul_nan_then_overdefined( | |
| ; CHECK-SAME: float [[A:%.*]], i1 [[BC:%.*]]) { | |
| ; CHECK-NEXT: [[ENTRY:.*:]] | |
| ; CHECK-NEXT: br i1 [[BC]], label %[[BB1:.*]], label %[[BB2:.*]] | |
| ; CHECK: [[BB1]]: | |
| ; CHECK-NEXT: br label %[[EXIT:.*]] | |
| ; CHECK: [[BB2]]: | |
| ; CHECK-NEXT: br label %[[EXIT]] | |
| ; CHECK: [[EXIT]]: | |
| ; CHECK-NEXT: [[P:%.*]] = phi float [ [[A]], %[[BB1]] ], [ +qnan, %[[BB2]] ] | |
| ; CHECK-NEXT: [[R:%.*]] = fmul nnan nsz float [[P]], 0.000000e+00 | |
| ; CHECK-NEXT: ret float [[R]] | |
| ; | |
| entry: | |
| br i1 %bc, label %bb1, label %bb2 | |
| bb1: | |
| br label %exit | |
| bb2: | |
| br label %exit | |
| exit: | |
| %p = phi float [ %a, %bb1 ], [ 0x7FF8000000000000, %bb2 ] | |
| %r = fmul nnan nsz float %p, 0.000000e+00 | |
| ret float %r | |
| } |