blob: abaff3333e27cd5d8660b3305825897753fd60f4 [file] [edit]
; 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
}