| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py |
| ; RUN: opt < %s -passes=instsimplify -S | FileCheck %s |
| |
| ; |
| ; constrained fsub |
| ; |
| |
| ; |
| ; fsub X, +0 ==> X |
| ; |
| |
| define float @fsub_x_p0_defaultenv(float %a) #0 { |
| ; CHECK-LABEL: @fsub_x_p0_defaultenv( |
| ; CHECK-NEXT: ret float [[A:%.*]] |
| ; |
| %ret = call float @llvm.experimental.constrained.fsub.f32(float %a, float 0.0, metadata !"round.tonearest", metadata !"fpexcept.ignore") |
| ret float %ret |
| } |
| |
| ; Missing nnan: must not fire. |
| define float @fsub_x_p0_ebmaytrap(float %a) #0 { |
| ; CHECK-LABEL: @fsub_x_p0_ebmaytrap( |
| ; CHECK-NEXT: [[RET:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[A:%.*]], float 0.000000e+00, metadata !"round.tonearest", metadata !"fpexcept.maytrap") |
| ; CHECK-NEXT: ret float [[RET]] |
| ; |
| %ret = call float @llvm.experimental.constrained.fsub.f32(float %a, float 0.0, metadata !"round.tonearest", metadata !"fpexcept.maytrap") |
| ret float %ret |
| } |
| |
| define float @fsub_nnan_x_p0_ebmaytrap(float %a) #0 { |
| ; CHECK-LABEL: @fsub_nnan_x_p0_ebmaytrap( |
| ; CHECK-NEXT: ret float [[A:%.*]] |
| ; |
| %ret = call nnan float @llvm.experimental.constrained.fsub.f32(float %a, float 0.0, metadata !"round.tonearest", metadata !"fpexcept.maytrap") |
| ret float %ret |
| } |
| |
| ; Missing nnan: must not fire. |
| define float @fsub_x_p0_ebstrict(float %a) #0 { |
| ; CHECK-LABEL: @fsub_x_p0_ebstrict( |
| ; CHECK-NEXT: [[RET:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[A:%.*]], float 0.000000e+00, metadata !"round.tonearest", metadata !"fpexcept.strict") |
| ; CHECK-NEXT: ret float [[RET]] |
| ; |
| %ret = call float @llvm.experimental.constrained.fsub.f32(float %a, float 0.0, metadata !"round.tonearest", metadata !"fpexcept.strict") |
| ret float %ret |
| } |
| |
| ; The instruction is expected to remain, but the result isn't used. |
| define float @fsub_nnan_x_p0_ebstrict(float %a) #0 { |
| ; CHECK-LABEL: @fsub_nnan_x_p0_ebstrict( |
| ; CHECK-NEXT: [[RET:%.*]] = call nnan float @llvm.experimental.constrained.fsub.f32(float [[A:%.*]], float 0.000000e+00, metadata !"round.tonearest", metadata !"fpexcept.strict") |
| ; CHECK-NEXT: ret float [[A]] |
| ; |
| %ret = call nnan float @llvm.experimental.constrained.fsub.f32(float %a, float 0.0, metadata !"round.tonearest", metadata !"fpexcept.strict") |
| ret float %ret |
| } |
| |
| ; Test with a fast math flag set but that flag is not "nnan". |
| define float @fsub_ninf_x_p0_ebstrict(float %a) #0 { |
| ; CHECK-LABEL: @fsub_ninf_x_p0_ebstrict( |
| ; CHECK-NEXT: [[RET:%.*]] = call ninf float @llvm.experimental.constrained.fsub.f32(float [[A:%.*]], float 0.000000e+00, metadata !"round.tonearest", metadata !"fpexcept.strict") |
| ; CHECK-NEXT: ret float [[RET]] |
| ; |
| %ret = call ninf float @llvm.experimental.constrained.fsub.f32(float %a, float 0.0, metadata !"round.tonearest", metadata !"fpexcept.strict") |
| ret float %ret |
| } |
| |
| ; Round to -inf and if x is zero then the result is -0.0: must not fire |
| define float @fsub_x_p0_neginf(float %a) #0 { |
| ; CHECK-LABEL: @fsub_x_p0_neginf( |
| ; CHECK-NEXT: [[RET:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[A:%.*]], float 0.000000e+00, metadata !"round.downward", metadata !"fpexcept.ignore") |
| ; CHECK-NEXT: ret float [[RET]] |
| ; |
| %ret = call float @llvm.experimental.constrained.fsub.f32(float %a, float 0.0, metadata !"round.downward", metadata !"fpexcept.ignore") |
| ret float %ret |
| } |
| |
| ; Dynamic rounding means the rounding mode might be to -inf: |
| ; Round to -inf and if x is zero then the result is -0.0: must not fire |
| define float @fsub_x_p0_dynamic(float %a) #0 { |
| ; CHECK-LABEL: @fsub_x_p0_dynamic( |
| ; CHECK-NEXT: [[RET:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[A:%.*]], float 0.000000e+00, metadata !"round.dynamic", metadata !"fpexcept.ignore") |
| ; CHECK-NEXT: ret float [[RET]] |
| ; |
| %ret = call float @llvm.experimental.constrained.fsub.f32(float %a, float 0.0, metadata !"round.dynamic", metadata !"fpexcept.ignore") |
| ret float %ret |
| } |
| |
| ; With nsz we don't have to worry about -0.0 so the transform is valid. |
| define float @fsub_nsz_x_p0_neginf(float %a) #0 { |
| ; CHECK-LABEL: @fsub_nsz_x_p0_neginf( |
| ; CHECK-NEXT: ret float [[A:%.*]] |
| ; |
| %ret = call nsz float @llvm.experimental.constrained.fsub.f32(float %a, float 0.0, metadata !"round.downward", metadata !"fpexcept.ignore") |
| ret float %ret |
| } |
| |
| ; With nsz we don't have to worry about -0.0 so the transform is valid. |
| define float @fsub_nsz_x_p0_dynamic(float %a) #0 { |
| ; CHECK-LABEL: @fsub_nsz_x_p0_dynamic( |
| ; CHECK-NEXT: ret float [[A:%.*]] |
| ; |
| %ret = call nsz float @llvm.experimental.constrained.fsub.f32(float %a, float 0.0, metadata !"round.dynamic", metadata !"fpexcept.ignore") |
| ret float %ret |
| } |
| |
| ; |
| ; fsub X, -0 ==> X, when we know X is not -0 |
| ; (fast math flag: nsz) |
| ; |
| |
| define float @fold_fsub_nsz_x_n0_defaultenv(float %a) #0 { |
| ; CHECK-LABEL: @fold_fsub_nsz_x_n0_defaultenv( |
| ; CHECK-NEXT: ret float [[A:%.*]] |
| ; |
| %sub = call nsz float @llvm.experimental.constrained.fsub.f32(float %a, float -0.0, metadata !"round.tonearest", metadata !"fpexcept.ignore") |
| ret float %sub |
| } |
| |
| ; Missing nnan: must not fire. |
| define float @fold_fsub_nsz_x_n0_ebmaytrap(float %a) #0 { |
| ; CHECK-LABEL: @fold_fsub_nsz_x_n0_ebmaytrap( |
| ; CHECK-NEXT: [[SUB:%.*]] = call nsz float @llvm.experimental.constrained.fsub.f32(float [[A:%.*]], float -0.000000e+00, metadata !"round.tonearest", metadata !"fpexcept.maytrap") |
| ; CHECK-NEXT: ret float [[SUB]] |
| ; |
| %sub = call nsz float @llvm.experimental.constrained.fsub.f32(float %a, float -0.0, metadata !"round.tonearest", metadata !"fpexcept.maytrap") |
| ret float %sub |
| } |
| |
| define float @fold_fsub_nnan_nsz_x_n0_ebmaytrap(float %a) #0 { |
| ; CHECK-LABEL: @fold_fsub_nnan_nsz_x_n0_ebmaytrap( |
| ; CHECK-NEXT: ret float [[A:%.*]] |
| ; |
| %sub = call nnan nsz float @llvm.experimental.constrained.fsub.f32(float %a, float -0.0, metadata !"round.tonearest", metadata !"fpexcept.maytrap") |
| ret float %sub |
| } |
| |
| ; Missing nnan: must not fire. |
| define float @fold_fsub_nsz_x_n0_ebstrict(float %a) #0 { |
| ; CHECK-LABEL: @fold_fsub_nsz_x_n0_ebstrict( |
| ; CHECK-NEXT: [[SUB:%.*]] = call nsz float @llvm.experimental.constrained.fsub.f32(float [[A:%.*]], float -0.000000e+00, metadata !"round.tonearest", metadata !"fpexcept.strict") |
| ; CHECK-NEXT: ret float [[SUB]] |
| ; |
| %sub = call nsz float @llvm.experimental.constrained.fsub.f32(float %a, float -0.0, metadata !"round.tonearest", metadata !"fpexcept.strict") |
| ret float %sub |
| } |
| |
| ; The instruction is expected to remain, but the result isn't used. |
| define float @fold_fsub_nsz_nnan_x_n0_ebstrict(float %a) #0 { |
| ; CHECK-LABEL: @fold_fsub_nsz_nnan_x_n0_ebstrict( |
| ; CHECK-NEXT: [[SUB:%.*]] = call nnan nsz float @llvm.experimental.constrained.fsub.f32(float [[A:%.*]], float -0.000000e+00, metadata !"round.tonearest", metadata !"fpexcept.strict") |
| ; CHECK-NEXT: ret float [[A]] |
| ; |
| %sub = call nsz nnan float @llvm.experimental.constrained.fsub.f32(float %a, float -0.0, metadata !"round.tonearest", metadata !"fpexcept.strict") |
| ret float %sub |
| } |
| |
| ; |
| ; fsub X, -0 ==> X, when we know X is not -0 |
| ; (No "nsz" flags) |
| ; |
| |
| define float @fold_fsub_fabs_x_n0_defaultenv(float %a) #0 { |
| ; CHECK-LABEL: @fold_fsub_fabs_x_n0_defaultenv( |
| ; CHECK-NEXT: [[ABSA:%.*]] = call float @llvm.fabs.f32(float [[A:%.*]]) #[[ATTR0:[0-9]+]] |
| ; CHECK-NEXT: ret float [[ABSA]] |
| ; |
| %absa = call float @llvm.fabs.f32(float %a) #0 |
| %sub = call float @llvm.experimental.constrained.fsub.f32(float %absa, float -0.0, metadata !"round.tonearest", metadata !"fpexcept.ignore") |
| ret float %sub |
| } |
| |
| ; Missing nnan: must not fire. |
| define float @fold_fsub_fabs_x_n0_ebmaytrap(float %a) #0 { |
| ; CHECK-LABEL: @fold_fsub_fabs_x_n0_ebmaytrap( |
| ; CHECK-NEXT: [[ABSA:%.*]] = call float @llvm.fabs.f32(float [[A:%.*]]) #[[ATTR0]] |
| ; CHECK-NEXT: [[SUB:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[ABSA]], float -0.000000e+00, metadata !"round.tonearest", metadata !"fpexcept.maytrap") |
| ; CHECK-NEXT: ret float [[SUB]] |
| ; |
| %absa = call float @llvm.fabs.f32(float %a) #0 |
| %sub = call float @llvm.experimental.constrained.fsub.f32(float %absa, float -0.0, metadata !"round.tonearest", metadata !"fpexcept.maytrap") |
| ret float %sub |
| } |
| |
| define float @fold_fsub_fabs_nnan_x_n0_ebmaytrap(float %a) #0 { |
| ; CHECK-LABEL: @fold_fsub_fabs_nnan_x_n0_ebmaytrap( |
| ; CHECK-NEXT: [[ABSA:%.*]] = call float @llvm.fabs.f32(float [[A:%.*]]) #[[ATTR0]] |
| ; CHECK-NEXT: ret float [[ABSA]] |
| ; |
| %absa = call float @llvm.fabs.f32(float %a) #0 |
| %sub = call nnan float @llvm.experimental.constrained.fsub.f32(float %absa, float -0.0, metadata !"round.tonearest", metadata !"fpexcept.maytrap") |
| ret float %sub |
| } |
| |
| ; Missing nnan: must not fire. |
| define float @fold_fsub_fabs_x_n0_ebstrict(float %a) #0 { |
| ; CHECK-LABEL: @fold_fsub_fabs_x_n0_ebstrict( |
| ; CHECK-NEXT: [[ABSA:%.*]] = call float @llvm.fabs.f32(float [[A:%.*]]) #[[ATTR0]] |
| ; CHECK-NEXT: [[SUB:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[ABSA]], float -0.000000e+00, metadata !"round.tonearest", metadata !"fpexcept.strict") |
| ; CHECK-NEXT: ret float [[SUB]] |
| ; |
| %absa = call float @llvm.fabs.f32(float %a) #0 |
| %sub = call float @llvm.experimental.constrained.fsub.f32(float %absa, float -0.0, metadata !"round.tonearest", metadata !"fpexcept.strict") |
| ret float %sub |
| } |
| |
| ; The instruction is expected to remain, but the result isn't used. |
| define float @fold_fsub_fabs_nnan_x_n0_ebstrict(float %a) #0 { |
| ; CHECK-LABEL: @fold_fsub_fabs_nnan_x_n0_ebstrict( |
| ; CHECK-NEXT: [[ABSA:%.*]] = call float @llvm.fabs.f32(float [[A:%.*]]) #[[ATTR0]] |
| ; CHECK-NEXT: [[SUB:%.*]] = call nnan float @llvm.experimental.constrained.fsub.f32(float [[ABSA]], float -0.000000e+00, metadata !"round.tonearest", metadata !"fpexcept.strict") |
| ; CHECK-NEXT: ret float [[ABSA]] |
| ; |
| %absa = call float @llvm.fabs.f32(float %a) #0 |
| %sub = call nnan float @llvm.experimental.constrained.fsub.f32(float %absa, float -0.0, metadata !"round.tonearest", metadata !"fpexcept.strict") |
| ret float %sub |
| } |
| |
| define float @fold_fsub_sitofp_x_n0_defaultenv(i32 %a) #0 { |
| ; CHECK-LABEL: @fold_fsub_sitofp_x_n0_defaultenv( |
| ; CHECK-NEXT: [[FPA:%.*]] = call float @llvm.experimental.constrained.sitofp.f32.i32(i32 [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") |
| ; CHECK-NEXT: ret float [[FPA]] |
| ; |
| %fpa = call float @llvm.experimental.constrained.sitofp.f32.i32(i32 %a, metadata !"round.tonearest", metadata !"fpexcept.ignore") |
| %sub = call float @llvm.experimental.constrained.fsub.f32(float %fpa, float -0.0, metadata !"round.tonearest", metadata !"fpexcept.ignore") |
| ret float %sub |
| } |
| |
| ; |
| ; fsub -0.0, (fneg X) ==> X |
| ; |
| |
| define float @fsub_fneg_n0_fnX_defaultenv(float %a) #0 { |
| ; CHECK-LABEL: @fsub_fneg_n0_fnX_defaultenv( |
| ; CHECK-NEXT: ret float [[A:%.*]] |
| ; |
| %nega = fneg float %a |
| %ret = call float @llvm.experimental.constrained.fsub.f32(float -0.0, float %nega, metadata !"round.tonearest", metadata !"fpexcept.ignore") |
| ret float %ret |
| } |
| |
| ; Missing nnan: must not fire. |
| define float @fsub_fneg_n0_fnX_ebmaytrap(float %a) #0 { |
| ; CHECK-LABEL: @fsub_fneg_n0_fnX_ebmaytrap( |
| ; CHECK-NEXT: [[NEGA:%.*]] = fneg float [[A:%.*]] |
| ; CHECK-NEXT: [[RET:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float -0.000000e+00, float [[NEGA]], metadata !"round.tonearest", metadata !"fpexcept.maytrap") |
| ; CHECK-NEXT: ret float [[RET]] |
| ; |
| %nega = fneg float %a |
| %ret = call float @llvm.experimental.constrained.fsub.f32(float -0.0, float %nega, metadata !"round.tonearest", metadata !"fpexcept.maytrap") |
| ret float %ret |
| } |
| |
| define float @fsub_fneg_nnan_n0_fnX_ebmaytrap(float %a) #0 { |
| ; CHECK-LABEL: @fsub_fneg_nnan_n0_fnX_ebmaytrap( |
| ; CHECK-NEXT: ret float [[A:%.*]] |
| ; |
| %nega = fneg float %a |
| %ret = call nnan float @llvm.experimental.constrained.fsub.f32(float -0.0, float %nega, metadata !"round.tonearest", metadata !"fpexcept.maytrap") |
| ret float %ret |
| } |
| |
| ; Missing nnan: must not fire. |
| define float @fsub_fneg_n0_fnX_ebstrict(float %a) #0 { |
| ; CHECK-LABEL: @fsub_fneg_n0_fnX_ebstrict( |
| ; CHECK-NEXT: [[NEGA:%.*]] = fneg float [[A:%.*]] |
| ; CHECK-NEXT: [[RET:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float -0.000000e+00, float [[NEGA]], metadata !"round.tonearest", metadata !"fpexcept.strict") |
| ; CHECK-NEXT: ret float [[RET]] |
| ; |
| %nega = fneg float %a |
| %ret = call float @llvm.experimental.constrained.fsub.f32(float -0.0, float %nega, metadata !"round.tonearest", metadata !"fpexcept.strict") |
| ret float %ret |
| } |
| |
| ; The instruction is expected to remain, but the result isn't used. |
| define float @fsub_fneg_nnan_n0_fnX_ebstrict(float %a) #0 { |
| ; CHECK-LABEL: @fsub_fneg_nnan_n0_fnX_ebstrict( |
| ; CHECK-NEXT: [[NEGA:%.*]] = fneg float [[A:%.*]] |
| ; CHECK-NEXT: [[RET:%.*]] = call nnan float @llvm.experimental.constrained.fsub.f32(float -0.000000e+00, float [[NEGA]], metadata !"round.tonearest", metadata !"fpexcept.strict") |
| ; CHECK-NEXT: ret float [[A]] |
| ; |
| %nega = fneg float %a |
| %ret = call nnan float @llvm.experimental.constrained.fsub.f32(float -0.0, float %nega, metadata !"round.tonearest", metadata !"fpexcept.strict") |
| ret float %ret |
| } |
| |
| ; |
| ; fsub -0.0, (fsub -0.0, X) ==> X |
| ; |
| |
| ; TODO: This won't fire without m_FNeg() knowing the constrained intrinsics. |
| define float @fsub_fsub_n0_fnX_defaultenv(float %a) #0 { |
| ; CHECK-LABEL: @fsub_fsub_n0_fnX_defaultenv( |
| ; CHECK-NEXT: [[NEGA:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float -0.000000e+00, float [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") |
| ; CHECK-NEXT: [[RET:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float -0.000000e+00, float [[NEGA]], metadata !"round.tonearest", metadata !"fpexcept.ignore") |
| ; CHECK-NEXT: ret float [[RET]] |
| ; |
| %nega = call float @llvm.experimental.constrained.fsub.f32(float -0.0, float %a, metadata !"round.tonearest", metadata !"fpexcept.ignore") |
| %ret = call float @llvm.experimental.constrained.fsub.f32(float -0.0, float %nega, metadata !"round.tonearest", metadata !"fpexcept.ignore") |
| ret float %ret |
| } |
| |
| ; Missing nnan: must not fire. |
| define float @fsub_fsub_n0_fnX_ebmaytrap(float %a) #0 { |
| ; CHECK-LABEL: @fsub_fsub_n0_fnX_ebmaytrap( |
| ; CHECK-NEXT: [[NEGA:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float -0.000000e+00, float [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.maytrap") |
| ; CHECK-NEXT: [[RET:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float -0.000000e+00, float [[NEGA]], metadata !"round.tonearest", metadata !"fpexcept.maytrap") |
| ; CHECK-NEXT: ret float [[RET]] |
| ; |
| %nega = call float @llvm.experimental.constrained.fsub.f32(float -0.0, float %a, metadata !"round.tonearest", metadata !"fpexcept.maytrap") |
| %ret = call float @llvm.experimental.constrained.fsub.f32(float -0.0, float %nega, metadata !"round.tonearest", metadata !"fpexcept.maytrap") |
| ret float %ret |
| } |
| |
| ; TODO: This won't fire without m_FNeg() knowing the constrained intrinsics. |
| define float @fsub_fsub_nnan_n0_fnX_ebmaytrap(float %a) #0 { |
| ; CHECK-LABEL: @fsub_fsub_nnan_n0_fnX_ebmaytrap( |
| ; CHECK-NEXT: [[NEGA:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float -0.000000e+00, float [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.maytrap") |
| ; CHECK-NEXT: [[RET:%.*]] = call nnan float @llvm.experimental.constrained.fsub.f32(float -0.000000e+00, float [[NEGA]], metadata !"round.tonearest", metadata !"fpexcept.maytrap") |
| ; CHECK-NEXT: ret float [[RET]] |
| ; |
| %nega = call float @llvm.experimental.constrained.fsub.f32(float -0.0, float %a, metadata !"round.tonearest", metadata !"fpexcept.maytrap") |
| %ret = call nnan float @llvm.experimental.constrained.fsub.f32(float -0.0, float %nega, metadata !"round.tonearest", metadata !"fpexcept.maytrap") |
| ret float %ret |
| } |
| |
| ; Missing nnan: must not fire. |
| define float @fsub_fsub_n0_fnX_ebstrict(float %a) #0 { |
| ; CHECK-LABEL: @fsub_fsub_n0_fnX_ebstrict( |
| ; CHECK-NEXT: [[NEGA:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float -0.000000e+00, float [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.strict") |
| ; CHECK-NEXT: [[RET:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float -0.000000e+00, float [[NEGA]], metadata !"round.tonearest", metadata !"fpexcept.strict") |
| ; CHECK-NEXT: ret float [[RET]] |
| ; |
| %nega = call float @llvm.experimental.constrained.fsub.f32(float -0.0, float %a, metadata !"round.tonearest", metadata !"fpexcept.strict") |
| %ret = call float @llvm.experimental.constrained.fsub.f32(float -0.0, float %nega, metadata !"round.tonearest", metadata !"fpexcept.strict") |
| ret float %ret |
| } |
| |
| ; TODO: This won't fire without m_FNeg() knowing the constrained intrinsics. |
| define float @fsub_fsub_nnan_n0_fnX_ebstrict(float %a) #0 { |
| ; CHECK-LABEL: @fsub_fsub_nnan_n0_fnX_ebstrict( |
| ; CHECK-NEXT: [[NEGA:%.*]] = call nnan float @llvm.experimental.constrained.fsub.f32(float -0.000000e+00, float [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.strict") |
| ; CHECK-NEXT: [[RET:%.*]] = call nnan float @llvm.experimental.constrained.fsub.f32(float -0.000000e+00, float [[NEGA]], metadata !"round.tonearest", metadata !"fpexcept.strict") |
| ; CHECK-NEXT: ret float [[RET]] |
| ; |
| %nega = call nnan float @llvm.experimental.constrained.fsub.f32(float -0.0, float %a, metadata !"round.tonearest", metadata !"fpexcept.strict") |
| %ret = call nnan float @llvm.experimental.constrained.fsub.f32(float -0.0, float %nega, metadata !"round.tonearest", metadata !"fpexcept.strict") |
| ret float %ret |
| } |
| |
| ; |
| ; fsub 0.0, (fneg X) ==> X if signed zeros are ignored. |
| ; |
| |
| define float @fsub_fneg_nsz_p0_fnX_defaultenv(float %a) #0 { |
| ; CHECK-LABEL: @fsub_fneg_nsz_p0_fnX_defaultenv( |
| ; CHECK-NEXT: ret float [[A:%.*]] |
| ; |
| %nega = fneg float %a |
| %ret = call nsz float @llvm.experimental.constrained.fsub.f32(float 0.0, float %nega, metadata !"round.tonearest", metadata !"fpexcept.ignore") |
| ret float %ret |
| } |
| |
| ; Missing nnan: must not fire. |
| define float @fsub_fneg_nsz_p0_fnX_ebmaytrap(float %a) #0 { |
| ; CHECK-LABEL: @fsub_fneg_nsz_p0_fnX_ebmaytrap( |
| ; CHECK-NEXT: [[NEGA:%.*]] = fneg float [[A:%.*]] |
| ; CHECK-NEXT: [[RET:%.*]] = call nsz float @llvm.experimental.constrained.fsub.f32(float 0.000000e+00, float [[NEGA]], metadata !"round.tonearest", metadata !"fpexcept.maytrap") |
| ; CHECK-NEXT: ret float [[RET]] |
| ; |
| %nega = fneg float %a |
| %ret = call nsz float @llvm.experimental.constrained.fsub.f32(float 0.0, float %nega, metadata !"round.tonearest", metadata !"fpexcept.maytrap") |
| ret float %ret |
| } |
| |
| define float @fsub_fneg_nsz_nnan_p0_fnX_ebmaytrap(float %a) #0 { |
| ; CHECK-LABEL: @fsub_fneg_nsz_nnan_p0_fnX_ebmaytrap( |
| ; CHECK-NEXT: ret float [[A:%.*]] |
| ; |
| %nega = fneg float %a |
| %ret = call nnan nsz float @llvm.experimental.constrained.fsub.f32(float 0.0, float %nega, metadata !"round.tonearest", metadata !"fpexcept.maytrap") |
| ret float %ret |
| } |
| |
| ; Missing nnan: must not fire. |
| define float @fsub_fneg_nsz_p0_fnX_ebstrict(float %a) #0 { |
| ; CHECK-LABEL: @fsub_fneg_nsz_p0_fnX_ebstrict( |
| ; CHECK-NEXT: [[NEGA:%.*]] = fneg float [[A:%.*]] |
| ; CHECK-NEXT: [[RET:%.*]] = call nsz float @llvm.experimental.constrained.fsub.f32(float 0.000000e+00, float [[NEGA]], metadata !"round.tonearest", metadata !"fpexcept.strict") |
| ; CHECK-NEXT: ret float [[RET]] |
| ; |
| %nega = fneg float %a |
| %ret = call nsz float @llvm.experimental.constrained.fsub.f32(float 0.0, float %nega, metadata !"round.tonearest", metadata !"fpexcept.strict") |
| ret float %ret |
| } |
| |
| ; The instruction is expected to remain, but the result isn't used. |
| define float @fsub_fneg_nnan_nsz_p0_fnX_ebstrict(float %a) #0 { |
| ; CHECK-LABEL: @fsub_fneg_nnan_nsz_p0_fnX_ebstrict( |
| ; CHECK-NEXT: [[NEGA:%.*]] = fneg float [[A:%.*]] |
| ; CHECK-NEXT: [[RET:%.*]] = call nnan nsz float @llvm.experimental.constrained.fsub.f32(float 0.000000e+00, float [[NEGA]], metadata !"round.tonearest", metadata !"fpexcept.strict") |
| ; CHECK-NEXT: ret float [[A]] |
| ; |
| %nega = fneg float %a |
| %ret = call nnan nsz float @llvm.experimental.constrained.fsub.f32(float 0.0, float %nega, metadata !"round.tonearest", metadata !"fpexcept.strict") |
| ret float %ret |
| } |
| |
| ; |
| ; fsub 0.0, (fsub 0.0, X) ==> X if signed zeros are ignored. |
| ; |
| |
| ; TODO: Need constrained intrinsic support in m_FNeg() and m_FSub to fire. |
| define float @fsub_fsub_p0_nsz_fnX_defaultenv(float %a) #0 { |
| ; CHECK-LABEL: @fsub_fsub_p0_nsz_fnX_defaultenv( |
| ; CHECK-NEXT: [[NEGA:%.*]] = call nsz float @llvm.experimental.constrained.fsub.f32(float 0.000000e+00, float [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") |
| ; CHECK-NEXT: [[RET:%.*]] = call nsz float @llvm.experimental.constrained.fsub.f32(float 0.000000e+00, float [[NEGA]], metadata !"round.tonearest", metadata !"fpexcept.ignore") |
| ; CHECK-NEXT: ret float [[RET]] |
| ; |
| %nega = call nsz float @llvm.experimental.constrained.fsub.f32(float 0.0, float %a, metadata !"round.tonearest", metadata !"fpexcept.ignore") |
| %ret = call nsz float @llvm.experimental.constrained.fsub.f32(float 0.0, float %nega, metadata !"round.tonearest", metadata !"fpexcept.ignore") |
| ret float %ret |
| } |
| |
| ; Missing nnan: must not fire. |
| define float @fsub_fsub_nsz_p0_fnX_ebmaytrap(float %a) #0 { |
| ; CHECK-LABEL: @fsub_fsub_nsz_p0_fnX_ebmaytrap( |
| ; CHECK-NEXT: [[NEGA:%.*]] = call nsz float @llvm.experimental.constrained.fsub.f32(float 0.000000e+00, float [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.maytrap") |
| ; CHECK-NEXT: [[RET:%.*]] = call nsz float @llvm.experimental.constrained.fsub.f32(float 0.000000e+00, float [[NEGA]], metadata !"round.tonearest", metadata !"fpexcept.maytrap") |
| ; CHECK-NEXT: ret float [[RET]] |
| ; |
| %nega = call nsz float @llvm.experimental.constrained.fsub.f32(float 0.0, float %a, metadata !"round.tonearest", metadata !"fpexcept.maytrap") |
| %ret = call nsz float @llvm.experimental.constrained.fsub.f32(float 0.0, float %nega, metadata !"round.tonearest", metadata !"fpexcept.maytrap") |
| ret float %ret |
| } |
| |
| ; TODO: Need constrained intrinsic support in m_FNeg() and m_FSub to fire. |
| define float @fsub_fsub_nnan_nsz_p0_fnX_ebmaytrap(float %a) #0 { |
| ; CHECK-LABEL: @fsub_fsub_nnan_nsz_p0_fnX_ebmaytrap( |
| ; CHECK-NEXT: [[NEGA:%.*]] = call nnan nsz float @llvm.experimental.constrained.fsub.f32(float 0.000000e+00, float [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.maytrap") |
| ; CHECK-NEXT: [[RET:%.*]] = call nnan nsz float @llvm.experimental.constrained.fsub.f32(float 0.000000e+00, float [[NEGA]], metadata !"round.tonearest", metadata !"fpexcept.maytrap") |
| ; CHECK-NEXT: ret float [[RET]] |
| ; |
| %nega = call nnan nsz float @llvm.experimental.constrained.fsub.f32(float 0.0, float %a, metadata !"round.tonearest", metadata !"fpexcept.maytrap") |
| %ret = call nnan nsz float @llvm.experimental.constrained.fsub.f32(float 0.0, float %nega, metadata !"round.tonearest", metadata !"fpexcept.maytrap") |
| ret float %ret |
| } |
| |
| ; Missing nnan: must not fire. |
| define float @fsub_fsub_nsz_p0_fnX_ebstrict(float %a) #0 { |
| ; CHECK-LABEL: @fsub_fsub_nsz_p0_fnX_ebstrict( |
| ; CHECK-NEXT: [[NEGA:%.*]] = call nsz float @llvm.experimental.constrained.fsub.f32(float 0.000000e+00, float [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.strict") |
| ; CHECK-NEXT: [[RET:%.*]] = call nsz float @llvm.experimental.constrained.fsub.f32(float 0.000000e+00, float [[NEGA]], metadata !"round.tonearest", metadata !"fpexcept.strict") |
| ; CHECK-NEXT: ret float [[RET]] |
| ; |
| %nega = call nsz float @llvm.experimental.constrained.fsub.f32(float 0.0, float %a, metadata !"round.tonearest", metadata !"fpexcept.strict") |
| %ret = call nsz float @llvm.experimental.constrained.fsub.f32(float 0.0, float %nega, metadata !"round.tonearest", metadata !"fpexcept.strict") |
| ret float %ret |
| } |
| |
| ; TODO: Need constrained intrinsic support in m_FNeg() and m_FSub to fire. |
| define float @fsub_fsub_nnan_nsz_p0_fnX_ebstrict(float %a) #0 { |
| ; CHECK-LABEL: @fsub_fsub_nnan_nsz_p0_fnX_ebstrict( |
| ; CHECK-NEXT: [[NEGA:%.*]] = call nnan nsz float @llvm.experimental.constrained.fsub.f32(float 0.000000e+00, float [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.strict") |
| ; CHECK-NEXT: [[RET:%.*]] = call nnan nsz float @llvm.experimental.constrained.fsub.f32(float 0.000000e+00, float [[NEGA]], metadata !"round.tonearest", metadata !"fpexcept.strict") |
| ; CHECK-NEXT: ret float [[RET]] |
| ; |
| %nega = call nnan nsz float @llvm.experimental.constrained.fsub.f32(float 0.0, float %a, metadata !"round.tonearest", metadata !"fpexcept.strict") |
| %ret = call nnan nsz float @llvm.experimental.constrained.fsub.f32(float 0.0, float %nega, metadata !"round.tonearest", metadata !"fpexcept.strict") |
| ret float %ret |
| } |
| |
| ; |
| ; fsub nnan x, x ==> 0.0 |
| ; |
| |
| ; Missing nnan: must not fire. |
| define float @fsub_x_x_defaultenv(float %a) #0 { |
| ; CHECK-LABEL: @fsub_x_x_defaultenv( |
| ; CHECK-NEXT: [[RET:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[A:%.*]], float [[A]], metadata !"round.tonearest", metadata !"fpexcept.ignore") |
| ; CHECK-NEXT: ret float [[RET]] |
| ; |
| %ret = call float @llvm.experimental.constrained.fsub.f32(float %a, float %a, metadata !"round.tonearest", metadata !"fpexcept.ignore") |
| ret float %ret |
| } |
| |
| define float @fsub_nnan_x_x_defaultenv(float %a) #0 { |
| ; CHECK-LABEL: @fsub_nnan_x_x_defaultenv( |
| ; CHECK-NEXT: ret float 0.000000e+00 |
| ; |
| %ret = call nnan float @llvm.experimental.constrained.fsub.f32(float %a, float %a, metadata !"round.tonearest", metadata !"fpexcept.ignore") |
| ret float %ret |
| } |
| |
| ; Missing nnan: must not fire. |
| define float @fsub_x_x_ebmaytrap(float %a) #0 { |
| ; CHECK-LABEL: @fsub_x_x_ebmaytrap( |
| ; CHECK-NEXT: [[RET:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[A:%.*]], float [[A]], metadata !"round.tonearest", metadata !"fpexcept.maytrap") |
| ; CHECK-NEXT: ret float [[RET]] |
| ; |
| %ret = call float @llvm.experimental.constrained.fsub.f32(float %a, float %a, metadata !"round.tonearest", metadata !"fpexcept.maytrap") |
| ret float %ret |
| } |
| |
| ; TODO: This will fold if we allow non-default floating point environments. |
| define float @fsub_nnan_x_x_ebmaytrap(float %a) #0 { |
| ; CHECK-LABEL: @fsub_nnan_x_x_ebmaytrap( |
| ; CHECK-NEXT: [[RET:%.*]] = call nnan float @llvm.experimental.constrained.fsub.f32(float [[A:%.*]], float [[A]], metadata !"round.tonearest", metadata !"fpexcept.maytrap") |
| ; CHECK-NEXT: ret float [[RET]] |
| ; |
| %ret = call nnan float @llvm.experimental.constrained.fsub.f32(float %a, float %a, metadata !"round.tonearest", metadata !"fpexcept.maytrap") |
| ret float %ret |
| } |
| |
| ; Missing nnan: must not fire. |
| define float @fsub_x_x_ebstrict(float %a) #0 { |
| ; CHECK-LABEL: @fsub_x_x_ebstrict( |
| ; CHECK-NEXT: [[RET:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[A:%.*]], float [[A]], metadata !"round.tonearest", metadata !"fpexcept.strict") |
| ; CHECK-NEXT: ret float [[RET]] |
| ; |
| %ret = call float @llvm.experimental.constrained.fsub.f32(float %a, float %a, metadata !"round.tonearest", metadata !"fpexcept.strict") |
| ret float %ret |
| } |
| |
| ; TODO: This will fold if we allow non-default floating point environments. |
| ; The instruction is expected to remain, but the result isn't used. |
| define float @fsub_nnan_x_x_ebstrict(float %a) #0 { |
| ; CHECK-LABEL: @fsub_nnan_x_x_ebstrict( |
| ; CHECK-NEXT: [[RET:%.*]] = call nnan float @llvm.experimental.constrained.fsub.f32(float [[A:%.*]], float [[A]], metadata !"round.tonearest", metadata !"fpexcept.strict") |
| ; CHECK-NEXT: ret float [[RET]] |
| ; |
| %ret = call nnan float @llvm.experimental.constrained.fsub.f32(float %a, float %a, metadata !"round.tonearest", metadata !"fpexcept.strict") |
| ret float %ret |
| } |
| |
| ; |
| ; Y - (Y - X) --> X |
| ; |
| |
| ; Missing nsz and reassoc: must not fire |
| define float @fsub_fsub_y_x_x_defaultenv(float %x, float %y) #0 { |
| ; CHECK-LABEL: @fsub_fsub_y_x_x_defaultenv( |
| ; CHECK-NEXT: [[INNER:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[Y:%.*]], float [[X:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") |
| ; CHECK-NEXT: [[RET:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[Y]], float [[INNER]], metadata !"round.tonearest", metadata !"fpexcept.ignore") |
| ; CHECK-NEXT: ret float [[RET]] |
| ; |
| %inner = call float @llvm.experimental.constrained.fsub.f32(float %y, float %x, metadata !"round.tonearest", metadata !"fpexcept.ignore") |
| %ret = call float @llvm.experimental.constrained.fsub.f32(float %y, float %inner, metadata !"round.tonearest", metadata !"fpexcept.ignore") |
| ret float %ret |
| } |
| |
| ; TODO: Need constrained intrinsic support in m_c_FAdd() and m_FSub to fire. |
| define float @fsub_fsub_fmf_y_x_x_defaultenv(float %x, float %y) #0 { |
| ; CHECK-LABEL: @fsub_fsub_fmf_y_x_x_defaultenv( |
| ; CHECK-NEXT: [[INNER:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[Y:%.*]], float [[X:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") |
| ; CHECK-NEXT: [[RET:%.*]] = call reassoc nsz float @llvm.experimental.constrained.fsub.f32(float [[Y]], float [[INNER]], metadata !"round.tonearest", metadata !"fpexcept.ignore") |
| ; CHECK-NEXT: ret float [[RET]] |
| ; |
| %inner = call float @llvm.experimental.constrained.fsub.f32(float %y, float %x, metadata !"round.tonearest", metadata !"fpexcept.ignore") |
| %ret = call nsz reassoc float @llvm.experimental.constrained.fsub.f32(float %y, float %inner, metadata !"round.tonearest", metadata !"fpexcept.ignore") |
| ret float %ret |
| } |
| |
| ; TODO: Consider how alternate rounding modes can break these transforms. |
| |
| ; The "fpexcept.maytrap" instruction must _not_ be folded into the |
| ; "fpexcept.ignore" instruction. This must not fire. |
| define float @fsub_fsub_fmf_y_x_x_ebmaytrap_defaultenv(float %x, float %y) #0 { |
| ; CHECK-LABEL: @fsub_fsub_fmf_y_x_x_ebmaytrap_defaultenv( |
| ; CHECK-NEXT: [[INNER:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[Y:%.*]], float [[X:%.*]], metadata !"round.tonearest", metadata !"fpexcept.maytrap") |
| ; CHECK-NEXT: [[RET:%.*]] = call reassoc nsz float @llvm.experimental.constrained.fsub.f32(float [[Y]], float [[INNER]], metadata !"round.tonearest", metadata !"fpexcept.ignore") |
| ; CHECK-NEXT: ret float [[RET]] |
| ; |
| %inner = call float @llvm.experimental.constrained.fsub.f32(float %y, float %x, metadata !"round.tonearest", metadata !"fpexcept.maytrap") |
| %ret = call nsz reassoc float @llvm.experimental.constrained.fsub.f32(float %y, float %inner, metadata !"round.tonearest", metadata !"fpexcept.ignore") |
| ret float %ret |
| } |
| |
| ; Missing nsz and reassoc: must not fire |
| define float @fsub_fsub_y_x_x_ebmaytrap(float %x, float %y) #0 { |
| ; CHECK-LABEL: @fsub_fsub_y_x_x_ebmaytrap( |
| ; CHECK-NEXT: [[INNER:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[Y:%.*]], float [[X:%.*]], metadata !"round.tonearest", metadata !"fpexcept.maytrap") |
| ; CHECK-NEXT: [[RET:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[Y]], float [[INNER]], metadata !"round.tonearest", metadata !"fpexcept.maytrap") |
| ; CHECK-NEXT: ret float [[RET]] |
| ; |
| %inner = call float @llvm.experimental.constrained.fsub.f32(float %y, float %x, metadata !"round.tonearest", metadata !"fpexcept.maytrap") |
| %ret = call float @llvm.experimental.constrained.fsub.f32(float %y, float %inner, metadata !"round.tonearest", metadata !"fpexcept.maytrap") |
| ret float %ret |
| } |
| |
| ; TODO: Need constrained intrinsic support in m_c_FAdd() and m_FSub to fire. |
| define float @fsub_fsub_fmf_y_x_x_ebmaytrap(float %x, float %y) #0 { |
| ; CHECK-LABEL: @fsub_fsub_fmf_y_x_x_ebmaytrap( |
| ; CHECK-NEXT: [[INNER:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[Y:%.*]], float [[X:%.*]], metadata !"round.tonearest", metadata !"fpexcept.maytrap") |
| ; CHECK-NEXT: [[RET:%.*]] = call reassoc nsz float @llvm.experimental.constrained.fsub.f32(float [[Y]], float [[INNER]], metadata !"round.tonearest", metadata !"fpexcept.maytrap") |
| ; CHECK-NEXT: ret float [[RET]] |
| ; |
| %inner = call float @llvm.experimental.constrained.fsub.f32(float %y, float %x, metadata !"round.tonearest", metadata !"fpexcept.maytrap") |
| %ret = call nsz reassoc float @llvm.experimental.constrained.fsub.f32(float %y, float %inner, metadata !"round.tonearest", metadata !"fpexcept.maytrap") |
| ret float %ret |
| } |
| |
| ; Missing nsz and reassoc: must not fire |
| define float @fsub_fsub_y_x_x_ebstrict(float %x, float %y) #0 { |
| ; CHECK-LABEL: @fsub_fsub_y_x_x_ebstrict( |
| ; CHECK-NEXT: [[INNER:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[Y:%.*]], float [[X:%.*]], metadata !"round.tonearest", metadata !"fpexcept.strict") |
| ; CHECK-NEXT: [[RET:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[Y]], float [[INNER]], metadata !"round.tonearest", metadata !"fpexcept.strict") |
| ; CHECK-NEXT: ret float [[RET]] |
| ; |
| %inner = call float @llvm.experimental.constrained.fsub.f32(float %y, float %x, metadata !"round.tonearest", metadata !"fpexcept.strict") |
| %ret = call float @llvm.experimental.constrained.fsub.f32(float %y, float %inner, metadata !"round.tonearest", metadata !"fpexcept.strict") |
| ret float %ret |
| } |
| |
| ; TODO: Need constrained intrinsic support in m_c_FAdd() and m_FSub to fire. |
| define float @fsub_fsub_fmf_y_x_x_ebstrict(float %x, float %y) #0 { |
| ; CHECK-LABEL: @fsub_fsub_fmf_y_x_x_ebstrict( |
| ; CHECK-NEXT: [[INNER:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[Y:%.*]], float [[X:%.*]], metadata !"round.tonearest", metadata !"fpexcept.strict") |
| ; CHECK-NEXT: [[RET:%.*]] = call reassoc nsz float @llvm.experimental.constrained.fsub.f32(float [[Y]], float [[INNER]], metadata !"round.tonearest", metadata !"fpexcept.strict") |
| ; CHECK-NEXT: ret float [[RET]] |
| ; |
| %inner = call float @llvm.experimental.constrained.fsub.f32(float %y, float %x, metadata !"round.tonearest", metadata !"fpexcept.strict") |
| %ret = call nsz reassoc float @llvm.experimental.constrained.fsub.f32(float %y, float %inner, metadata !"round.tonearest", metadata !"fpexcept.strict") |
| ret float %ret |
| } |
| |
| ; |
| ; (X + Y) - Y --> X |
| ; TODO: Missing IR matcher support means these won't fire. |
| ; |
| |
| ; Missing nsz and reassoc: must not fire |
| define float @fadd_fsub_x_y_y_defaultenv(float %x, float %y) #0 { |
| ; CHECK-LABEL: @fadd_fsub_x_y_y_defaultenv( |
| ; CHECK-NEXT: [[INNER:%.*]] = call float @llvm.experimental.constrained.fadd.f32(float [[X:%.*]], float [[Y:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") |
| ; CHECK-NEXT: [[RET:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[INNER]], float [[Y]], metadata !"round.tonearest", metadata !"fpexcept.ignore") |
| ; CHECK-NEXT: ret float [[RET]] |
| ; |
| %inner = call float @llvm.experimental.constrained.fadd.f32(float %x, float %y, metadata !"round.tonearest", metadata !"fpexcept.ignore") |
| %ret = call float @llvm.experimental.constrained.fsub.f32(float %inner, float %y, metadata !"round.tonearest", metadata !"fpexcept.ignore") |
| ret float %ret |
| } |
| |
| ; TODO: Need constrained intrinsic support in m_c_FAdd() and m_FSub to fire. |
| define float @fadd_fsub_fmf_x_y_y_defaultenv(float %x, float %y) #0 { |
| ; CHECK-LABEL: @fadd_fsub_fmf_x_y_y_defaultenv( |
| ; CHECK-NEXT: [[INNER:%.*]] = call float @llvm.experimental.constrained.fadd.f32(float [[X:%.*]], float [[Y:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") |
| ; CHECK-NEXT: [[RET:%.*]] = call reassoc nsz float @llvm.experimental.constrained.fsub.f32(float [[INNER]], float [[Y]], metadata !"round.tonearest", metadata !"fpexcept.ignore") |
| ; CHECK-NEXT: ret float [[RET]] |
| ; |
| %inner = call float @llvm.experimental.constrained.fadd.f32(float %x, float %y, metadata !"round.tonearest", metadata !"fpexcept.ignore") |
| %ret = call nsz reassoc float @llvm.experimental.constrained.fsub.f32(float %inner, float %y, metadata !"round.tonearest", metadata !"fpexcept.ignore") |
| ret float %ret |
| } |
| |
| ; The "fpexcept.maytrap" instruction must _not_ be folded into the |
| ; "fpexcept.ignore" instruction. This must not fire. |
| define float @fadd_fsub_fmf_x_y_y_ebmaytrap_defaultenv(float %x, float %y) #0 { |
| ; CHECK-LABEL: @fadd_fsub_fmf_x_y_y_ebmaytrap_defaultenv( |
| ; CHECK-NEXT: [[INNER:%.*]] = call float @llvm.experimental.constrained.fadd.f32(float [[X:%.*]], float [[Y:%.*]], metadata !"round.tonearest", metadata !"fpexcept.maytrap") |
| ; CHECK-NEXT: [[RET:%.*]] = call reassoc nsz float @llvm.experimental.constrained.fsub.f32(float [[INNER]], float [[Y]], metadata !"round.tonearest", metadata !"fpexcept.ignore") |
| ; CHECK-NEXT: ret float [[RET]] |
| ; |
| %inner = call float @llvm.experimental.constrained.fadd.f32(float %x, float %y, metadata !"round.tonearest", metadata !"fpexcept.maytrap") |
| %ret = call nsz reassoc float @llvm.experimental.constrained.fsub.f32(float %inner, float %y, metadata !"round.tonearest", metadata !"fpexcept.ignore") |
| ret float %ret |
| } |
| |
| ; Missing nsz and reassoc: must not fire |
| define float @fadd_fsub_x_y_y_ebmaytrap(float %x, float %y) #0 { |
| ; CHECK-LABEL: @fadd_fsub_x_y_y_ebmaytrap( |
| ; CHECK-NEXT: [[INNER:%.*]] = call float @llvm.experimental.constrained.fadd.f32(float [[X:%.*]], float [[Y:%.*]], metadata !"round.tonearest", metadata !"fpexcept.maytrap") |
| ; CHECK-NEXT: [[RET:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[INNER]], float [[Y]], metadata !"round.tonearest", metadata !"fpexcept.maytrap") |
| ; CHECK-NEXT: ret float [[RET]] |
| ; |
| %inner = call float @llvm.experimental.constrained.fadd.f32(float %x, float %y, metadata !"round.tonearest", metadata !"fpexcept.maytrap") |
| %ret = call float @llvm.experimental.constrained.fsub.f32(float %inner, float %y, metadata !"round.tonearest", metadata !"fpexcept.maytrap") |
| ret float %ret |
| } |
| |
| ; TODO: Need constrained intrinsic support in m_c_FAdd() and m_FSub to fire. |
| define float @fadd_fsub_fmf_x_y_y_ebmaytrap(float %x, float %y) #0 { |
| ; CHECK-LABEL: @fadd_fsub_fmf_x_y_y_ebmaytrap( |
| ; CHECK-NEXT: [[INNER:%.*]] = call float @llvm.experimental.constrained.fadd.f32(float [[X:%.*]], float [[Y:%.*]], metadata !"round.tonearest", metadata !"fpexcept.maytrap") |
| ; CHECK-NEXT: [[RET:%.*]] = call reassoc nsz float @llvm.experimental.constrained.fsub.f32(float [[INNER]], float [[Y]], metadata !"round.tonearest", metadata !"fpexcept.maytrap") |
| ; CHECK-NEXT: ret float [[RET]] |
| ; |
| %inner = call float @llvm.experimental.constrained.fadd.f32(float %x, float %y, metadata !"round.tonearest", metadata !"fpexcept.maytrap") |
| %ret = call nsz reassoc float @llvm.experimental.constrained.fsub.f32(float %inner, float %y, metadata !"round.tonearest", metadata !"fpexcept.maytrap") |
| ret float %ret |
| } |
| |
| ; Missing nsz and reassoc: must not fire |
| define float @fadd_fsub_x_y_y_ebstrict(float %x, float %y) #0 { |
| ; CHECK-LABEL: @fadd_fsub_x_y_y_ebstrict( |
| ; CHECK-NEXT: [[INNER:%.*]] = call float @llvm.experimental.constrained.fadd.f32(float [[X:%.*]], float [[Y:%.*]], metadata !"round.tonearest", metadata !"fpexcept.strict") |
| ; CHECK-NEXT: [[RET:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[INNER]], float [[Y]], metadata !"round.tonearest", metadata !"fpexcept.strict") |
| ; CHECK-NEXT: ret float [[RET]] |
| ; |
| %inner = call float @llvm.experimental.constrained.fadd.f32(float %x, float %y, metadata !"round.tonearest", metadata !"fpexcept.strict") |
| %ret = call float @llvm.experimental.constrained.fsub.f32(float %inner, float %y, metadata !"round.tonearest", metadata !"fpexcept.strict") |
| ret float %ret |
| } |
| |
| ; TODO: Need constrained intrinsic support in m_c_FAdd() and m_FSub to fire. |
| define float @fadd_fsub_fmf_x_y_y_ebstrict(float %x, float %y) #0 { |
| ; CHECK-LABEL: @fadd_fsub_fmf_x_y_y_ebstrict( |
| ; CHECK-NEXT: [[INNER:%.*]] = call float @llvm.experimental.constrained.fadd.f32(float [[X:%.*]], float [[Y:%.*]], metadata !"round.tonearest", metadata !"fpexcept.strict") |
| ; CHECK-NEXT: [[RET:%.*]] = call reassoc nsz float @llvm.experimental.constrained.fsub.f32(float [[INNER]], float [[Y]], metadata !"round.tonearest", metadata !"fpexcept.strict") |
| ; CHECK-NEXT: ret float [[RET]] |
| ; |
| %inner = call float @llvm.experimental.constrained.fadd.f32(float %x, float %y, metadata !"round.tonearest", metadata !"fpexcept.strict") |
| %ret = call nsz reassoc float @llvm.experimental.constrained.fsub.f32(float %inner, float %y, metadata !"round.tonearest", metadata !"fpexcept.strict") |
| ret float %ret |
| } |
| |
| declare float @llvm.fabs.f32(float) |
| declare <2 x float> @llvm.fabs.v2f32(<2 x float>) |
| |
| declare float @llvm.experimental.constrained.fadd.f32(float, float, metadata, metadata) |
| declare float @llvm.experimental.constrained.fsub.f32(float, float, metadata, metadata) |
| |
| declare float @llvm.experimental.constrained.sitofp.f32.i32(i32, metadata, metadata) |
| |
| attributes #0 = { strictfp } |