[llvm] [AMDGPU] Avoid fract fold when result is observable at +/-inf (PR #219515)
Arseniy Obolenskiy via llvm-commits
llvm-commits at lists.llvm.org
Fri Aug 28 09:22:08 PDT 2026
https://github.com/aobolensk created https://github.com/llvm/llvm-project/pull/219515
fract returns nan at +/-inf, while minnum/minimumnum clamp to the constant there, so the fold is only safe when that difference can't be observed
>From 175e7a81082bd13c6d0e410eeaa34c2df636741d Mon Sep 17 00:00:00 2001
From: Arseniy Obolenskiy <arseniy.obolenskiy at amd.com>
Date: Fri, 28 Aug 2026 18:21:14 +0200
Subject: [PATCH] [AMDGPU] Avoid fract fold when result is observable at +/-inf
fract returns nan at +/-inf, while minnum/minimumnum clamp to the constant there, so the fold is only safe when that difference can't be observed
---
.../Target/AMDGPU/AMDGPUCodeGenPrepare.cpp | 85 +-
llvm/test/CodeGen/AMDGPU/fract-match.ll | 1536 ++++++++++++-----
2 files changed, 1191 insertions(+), 430 deletions(-)
diff --git a/llvm/lib/Target/AMDGPU/AMDGPUCodeGenPrepare.cpp b/llvm/lib/Target/AMDGPU/AMDGPUCodeGenPrepare.cpp
index 21a8896ed3a6d..e5e353e8d55ee 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUCodeGenPrepare.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPUCodeGenPrepare.cpp
@@ -19,6 +19,7 @@
#include "llvm/ADT/SetVector.h"
#include "llvm/Analysis/AssumptionCache.h"
#include "llvm/Analysis/ConstantFolding.h"
+#include "llvm/Analysis/FloatingPointPredicateUtils.h"
#include "llvm/Analysis/TargetLibraryInfo.h"
#include "llvm/Analysis/TargetTransformInfo.h"
#include "llvm/Analysis/UniformityAnalysis.h"
@@ -213,7 +214,11 @@ class AMDGPUCodeGenPrepareImpl
bool canWidenScalarExtLoad(LoadInst &I) const;
Value *matchFractPatImpl(Value &V, const APFloat &C) const;
- Value *matchFractPatNanAvoidant(Value &V);
+ Value *matchFractPatNanAvoidant(Value &V,
+ Instruction *RootToReplace = nullptr);
+ bool isFractNanAvoidantFoldLegalAtInf(const IntrinsicInst *MinI,
+ const Value *Sub, const Value *X,
+ Instruction *Root) const;
Value *applyFractPat(IRBuilder<> &Builder, Value *FractArg);
bool canOptimizeWithRsq(FastMathFlags DivFMF, FastMathFlags SqrtFMF) const;
@@ -1619,11 +1624,11 @@ bool AMDGPUCodeGenPrepareImpl::visitSelectInst(SelectInst &I) {
Builder.setFastMathFlags(FPOp->getFastMathFlags());
if (IsNanPred == FCmpInst::FCMP_UNO && TrueVal == CmpVal &&
- CmpVal == matchFractPatNanAvoidant(*FalseVal)) {
+ CmpVal == matchFractPatNanAvoidant(*FalseVal, &I)) {
// isnan(x) ? x : fract(x)
Fract = applyFractPat(Builder, CmpVal);
} else if (IsNanPred == FCmpInst::FCMP_ORD && FalseVal == CmpVal) {
- if (CmpVal == matchFractPatNanAvoidant(*TrueVal)) {
+ if (CmpVal == matchFractPatNanAvoidant(*TrueVal, &I)) {
// !isnan(x) ? fract(x) : x
Fract = applyFractPat(Builder, CmpVal);
} else {
@@ -2100,7 +2105,11 @@ Value *AMDGPUCodeGenPrepareImpl::matchFractPatImpl(Value &FractSrc,
///
/// If fract is a useful instruction for the subtarget. Does not account for the
/// nan handling; the instruction has a nan check on the input value.
-Value *AMDGPUCodeGenPrepareImpl::matchFractPatNanAvoidant(Value &V) {
+///
+/// If \p RootToReplace is set, the fract must also be unobservable at +/-inf.
+Value *
+AMDGPUCodeGenPrepareImpl::matchFractPatNanAvoidant(Value &V,
+ Instruction *RootToReplace) {
Value *Arg0;
const APFloat *C;
@@ -2112,7 +2121,71 @@ Value *AMDGPUCodeGenPrepareImpl::matchFractPatNanAvoidant(Value &V) {
m_FMinimum(m_Value(Arg0), m_APFloatAllowPoison(C)))))
return nullptr;
- return matchFractPatImpl(*Arg0, *C);
+ Value *FractArg = matchFractPatImpl(*Arg0, *C);
+ if (!FractArg)
+ return nullptr;
+
+ if (RootToReplace &&
+ !isFractNanAvoidantFoldLegalAtInf(cast<IntrinsicInst>(&V), Arg0, FractArg,
+ RootToReplace))
+ return nullptr;
+
+ return FractArg;
+}
+
+/// True if \p U is a select that never picks \p V when \p X is infinity, e.g.
+/// fract's library inf-clamp: select (fcmp oeq (fabs X), +inf), 0.0, V
+static bool isInfDiscardingSelect(User *U, const Value *X, const Value *V) {
+ auto *Sel = dyn_cast<SelectInst>(U);
+ if (!Sel)
+ return false;
+
+ bool IsTrueArm = Sel->getTrueValue() == V;
+ if (!IsTrueArm && Sel->getFalseValue() != V)
+ return false;
+ if (IsTrueArm && Sel->getFalseValue() == V)
+ return false;
+
+ auto *Cmp = dyn_cast<FCmpInst>(Sel->getCondition());
+ if (!Cmp)
+ return false;
+
+ auto [ClassVal, ClassesIfTrue, ClassesIfFalse] =
+ fcmpImpliesClass(Cmp->getPredicate(), *Sel->getFunction(),
+ Cmp->getOperand(0), Cmp->getOperand(1));
+ if (ClassVal != X)
+ return false;
+
+ return !((IsTrueArm ? ClassesIfTrue : ClassesIfFalse) & fcInf);
+}
+
+/// At +/-inf \p Sub is nan, so \p MinI clamps while fract would return nan;
+/// true if replacing \p Root with fract of \p X is unobservable there. Callers
+/// must not pass a \p Root that can select around \p MinI at +/-inf, since the
+/// poison cases assume \p Root is poison whenever \p MinI is.
+bool AMDGPUCodeGenPrepareImpl::isFractNanAvoidantFoldLegalAtInf(
+ const IntrinsicInst *MinI, const Value *Sub, const Value *X,
+ Instruction *Root) const {
+ // minimum propagates the nan from x - floor(x), exactly like fract.
+ if (MinI->getIntrinsicID() == Intrinsic::minimum)
+ return true;
+
+ // nnan poisons the min at +/-inf; ninf proves nothing here.
+ if (MinI->hasNoNaNs())
+ return true;
+
+ // At +/-inf the fsub is nan with infinite operands, so nnan/ninf poison it.
+ const auto *FPSub = cast<FPMathOperator>(Sub);
+ if (FPSub->hasNoNaNs() || FPSub->hasNoInfs())
+ return true;
+
+ // The result is only observed where an explicit infinity check discards it:
+ // isinf(x) ? 0.0 : (isnan(x) ? x : minnum(x - floor(x), C))
+ if (all_of(Root->users(),
+ [=](User *U) { return isInfDiscardingSelect(U, X, Root); }))
+ return true;
+
+ return isKnownNeverInfinity(X, SQ.getWithInstruction(Root));
}
Value *AMDGPUCodeGenPrepareImpl::applyFractPat(IRBuilder<> &Builder,
@@ -2144,7 +2217,7 @@ bool AMDGPUCodeGenPrepareImpl::visitFMinLike(IntrinsicInst &I) {
return false;
} else {
// minnum(x - floor(x), MIN_CONSTANT)
- FractArg = matchFractPatNanAvoidant(I);
+ FractArg = matchFractPatNanAvoidant(I, &I);
if (!FractArg)
return false;
diff --git a/llvm/test/CodeGen/AMDGPU/fract-match.ll b/llvm/test/CodeGen/AMDGPU/fract-match.ll
index b40763b4ca5f4..b2dfb24b1eacb 100644
--- a/llvm/test/CodeGen/AMDGPU/fract-match.ll
+++ b/llvm/test/CodeGen/AMDGPU/fract-match.ll
@@ -523,24 +523,16 @@ entry:
}
define float @safe_math_fract_f32_noinf_check(float %x, ptr addrspace(1) writeonly captures(none) %ip) {
-; GFX6-IR-LABEL: define float @safe_math_fract_f32_noinf_check(
-; GFX6-IR-SAME: float [[X:%.*]], ptr addrspace(1) writeonly captures(none) [[IP:%.*]]) {
-; GFX6-IR-NEXT: [[ENTRY:.*:]]
-; GFX6-IR-NEXT: [[FLOOR:%.*]] = tail call float @llvm.floor.f32(float [[X]])
-; GFX6-IR-NEXT: [[SUB:%.*]] = fsub float [[X]], [[FLOOR]]
-; GFX6-IR-NEXT: [[MIN:%.*]] = tail call float @llvm.minnum.f32(float [[SUB]], float f0x3F7FFFFF)
-; GFX6-IR-NEXT: [[UNO:%.*]] = fcmp uno float [[X]], 0.000000e+00
-; GFX6-IR-NEXT: [[COND:%.*]] = select i1 [[UNO]], float [[X]], float [[MIN]]
-; GFX6-IR-NEXT: store float [[FLOOR]], ptr addrspace(1) [[IP]], align 4
-; GFX6-IR-NEXT: ret float [[COND]]
-;
-; IR-FRACT-LABEL: define float @safe_math_fract_f32_noinf_check(
-; IR-FRACT-SAME: float [[X:%.*]], ptr addrspace(1) writeonly captures(none) [[IP:%.*]]) {
-; IR-FRACT-NEXT: [[ENTRY:.*:]]
-; IR-FRACT-NEXT: [[FLOOR:%.*]] = tail call float @llvm.floor.f32(float [[X]])
-; IR-FRACT-NEXT: [[COND:%.*]] = call float @llvm.amdgcn.fract.f32(float [[X]])
-; IR-FRACT-NEXT: store float [[FLOOR]], ptr addrspace(1) [[IP]], align 4
-; IR-FRACT-NEXT: ret float [[COND]]
+; IR-LABEL: define float @safe_math_fract_f32_noinf_check(
+; IR-SAME: float [[X:%.*]], ptr addrspace(1) writeonly captures(none) [[IP:%.*]]) {
+; IR-NEXT: [[ENTRY:.*:]]
+; IR-NEXT: [[FLOOR:%.*]] = tail call float @llvm.floor.f32(float [[X]])
+; IR-NEXT: [[SUB:%.*]] = fsub float [[X]], [[FLOOR]]
+; IR-NEXT: [[MIN:%.*]] = tail call float @llvm.minnum.f32(float [[SUB]], float f0x3F7FFFFF)
+; IR-NEXT: [[UNO:%.*]] = fcmp uno float [[X]], 0.000000e+00
+; IR-NEXT: [[COND:%.*]] = select i1 [[UNO]], float [[X]], float [[MIN]]
+; IR-NEXT: store float [[FLOOR]], ptr addrspace(1) [[IP]], align 4
+; IR-NEXT: ret float [[COND]]
;
; GFX6-LABEL: safe_math_fract_f32_noinf_check:
; GFX6: ; %bb.0: ; %entry
@@ -557,33 +549,47 @@ define float @safe_math_fract_f32_noinf_check(float %x, ptr addrspace(1) writeon
; GFX6-NEXT: buffer_store_dword v3, v[1:2], s[4:7], 0 addr64
; GFX6-NEXT: s_waitcnt vmcnt(0) expcnt(0)
; GFX6-NEXT: s_setpc_b64 s[30:31]
+;
; GFX7-LABEL: safe_math_fract_f32_noinf_check:
; GFX7: ; %bb.0: ; %entry
; GFX7-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX7-NEXT: v_floor_f32_e32 v3, v0
+; GFX7-NEXT: v_sub_f32_e32 v4, v0, v3
; GFX7-NEXT: s_mov_b32 s6, 0
+; GFX7-NEXT: v_min_f32_e32 v4, 0x3f7fffff, v4
+; GFX7-NEXT: v_cmp_u_f32_e32 vcc, v0, v0
; GFX7-NEXT: s_mov_b32 s7, 0xf000
; GFX7-NEXT: s_mov_b32 s4, s6
; GFX7-NEXT: s_mov_b32 s5, s6
-; GFX7-NEXT: v_floor_f32_e32 v3, v0
-; GFX7-NEXT: v_fract_f32_e32 v0, v0
+; GFX7-NEXT: v_cndmask_b32_e32 v0, v4, v0, vcc
; GFX7-NEXT: buffer_store_dword v3, v[1:2], s[4:7], 0 addr64
; GFX7-NEXT: s_waitcnt vmcnt(0)
; GFX7-NEXT: s_setpc_b64 s[30:31]
+;
; GFX8-LABEL: safe_math_fract_f32_noinf_check:
; GFX8: ; %bb.0: ; %entry
; GFX8-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
; GFX8-NEXT: v_floor_f32_e32 v3, v0
-; GFX8-NEXT: v_fract_f32_e32 v0, v0
+; GFX8-NEXT: v_sub_f32_e32 v4, v0, v3
+; GFX8-NEXT: v_min_f32_e32 v4, 0x3f7fffff, v4
+; GFX8-NEXT: v_cmp_u_f32_e32 vcc, v0, v0
+; GFX8-NEXT: v_cndmask_b32_e32 v0, v4, v0, vcc
; GFX8-NEXT: global_store_dword v[1:2], v3, off
; GFX8-NEXT: s_waitcnt vmcnt(0)
; GFX8-NEXT: s_setpc_b64 s[30:31]
+;
; GFX11-LABEL: safe_math_fract_f32_noinf_check:
; GFX11: ; %bb.0: ; %entry
; GFX11-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
; GFX11-NEXT: v_floor_f32_e32 v3, v0
-; GFX11-NEXT: v_fract_f32_e32 v0, v0
+; GFX11-NEXT: v_cmp_u_f32_e32 vcc_lo, v0, v0
+; GFX11-NEXT: s_delay_alu instid0(VALU_DEP_2) | instskip(SKIP_2) | instid1(VALU_DEP_1)
+; GFX11-NEXT: v_sub_f32_e32 v4, v0, v3
; GFX11-NEXT: global_store_b32 v[1:2], v3, off
+; GFX11-NEXT: v_min_f32_e32 v4, 0x3f7fffff, v4
+; GFX11-NEXT: v_cndmask_b32_e32 v0, v4, v0, vcc_lo
; GFX11-NEXT: s_setpc_b64 s[30:31]
+;
; GFX12-LABEL: safe_math_fract_f32_noinf_check:
; GFX12: ; %bb.0: ; %entry
; GFX12-NEXT: s_wait_loadcnt_dscnt 0x0
@@ -592,8 +598,13 @@ define float @safe_math_fract_f32_noinf_check(float %x, ptr addrspace(1) writeon
; GFX12-NEXT: s_wait_bvhcnt 0x0
; GFX12-NEXT: s_wait_kmcnt 0x0
; GFX12-NEXT: v_floor_f32_e32 v3, v0
-; GFX12-NEXT: v_fract_f32_e32 v0, v0
+; GFX12-NEXT: v_cmp_u_f32_e32 vcc_lo, v0, v0
+; GFX12-NEXT: s_delay_alu instid0(VALU_DEP_2) | instskip(SKIP_3) | instid1(VALU_DEP_1)
+; GFX12-NEXT: v_sub_f32_e32 v4, v0, v3
; GFX12-NEXT: global_store_b32 v[1:2], v3, off
+; GFX12-NEXT: v_min_num_f32_e32 v4, 0x3f7fffff, v4
+; GFX12-NEXT: s_wait_alu depctr_va_vcc(0)
+; GFX12-NEXT: v_cndmask_b32_e32 v0, v4, v0, vcc_lo
; GFX12-NEXT: s_setpc_b64 s[30:31]
entry:
%floor = tail call float @llvm.floor.f32(float %x)
@@ -702,19 +713,13 @@ entry:
}
define float @basic_fract_f32_nonans(float nofpclass(nan) %x) {
-; GFX6-IR-LABEL: define float @basic_fract_f32_nonans(
-; GFX6-IR-SAME: float nofpclass(nan) [[X:%.*]]) {
-; GFX6-IR-NEXT: [[ENTRY:.*:]]
-; GFX6-IR-NEXT: [[FLOOR:%.*]] = tail call float @llvm.floor.f32(float [[X]])
-; GFX6-IR-NEXT: [[SUB:%.*]] = fsub float [[X]], [[FLOOR]]
-; GFX6-IR-NEXT: [[MIN:%.*]] = tail call float @llvm.minnum.f32(float [[SUB]], float f0x3F7FFFFF)
-; GFX6-IR-NEXT: ret float [[MIN]]
-;
-; IR-FRACT-LABEL: define float @basic_fract_f32_nonans(
-; IR-FRACT-SAME: float nofpclass(nan) [[X:%.*]]) {
-; IR-FRACT-NEXT: [[ENTRY:.*:]]
-; IR-FRACT-NEXT: [[MIN:%.*]] = call nnan float @llvm.amdgcn.fract.f32(float [[X]])
-; IR-FRACT-NEXT: ret float [[MIN]]
+; IR-LABEL: define float @basic_fract_f32_nonans(
+; IR-SAME: float nofpclass(nan) [[X:%.*]]) {
+; IR-NEXT: [[ENTRY:.*:]]
+; IR-NEXT: [[FLOOR:%.*]] = tail call float @llvm.floor.f32(float [[X]])
+; IR-NEXT: [[SUB:%.*]] = fsub float [[X]], [[FLOOR]]
+; IR-NEXT: [[MIN:%.*]] = tail call float @llvm.minnum.f32(float [[SUB]], float f0x3F7FFFFF)
+; IR-NEXT: ret float [[MIN]]
;
; GFX6-LABEL: basic_fract_f32_nonans:
; GFX6: ; %bb.0: ; %entry
@@ -723,21 +728,32 @@ define float @basic_fract_f32_nonans(float nofpclass(nan) %x) {
; GFX6-NEXT: v_sub_f32_e32 v0, v0, v1
; GFX6-NEXT: v_min_f32_e32 v0, 0x3f7fffff, v0
; GFX6-NEXT: s_setpc_b64 s[30:31]
+;
; GFX7-LABEL: basic_fract_f32_nonans:
; GFX7: ; %bb.0: ; %entry
; GFX7-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX7-NEXT: v_fract_f32_e32 v0, v0
+; GFX7-NEXT: v_floor_f32_e32 v1, v0
+; GFX7-NEXT: v_sub_f32_e32 v0, v0, v1
+; GFX7-NEXT: v_min_f32_e32 v0, 0x3f7fffff, v0
; GFX7-NEXT: s_setpc_b64 s[30:31]
+;
; GFX8-LABEL: basic_fract_f32_nonans:
; GFX8: ; %bb.0: ; %entry
; GFX8-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX8-NEXT: v_fract_f32_e32 v0, v0
+; GFX8-NEXT: v_floor_f32_e32 v1, v0
+; GFX8-NEXT: v_sub_f32_e32 v0, v0, v1
+; GFX8-NEXT: v_min_f32_e32 v0, 0x3f7fffff, v0
; GFX8-NEXT: s_setpc_b64 s[30:31]
+;
; GFX11-LABEL: basic_fract_f32_nonans:
; GFX11: ; %bb.0: ; %entry
; GFX11-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX11-NEXT: v_fract_f32_e32 v0, v0
+; GFX11-NEXT: v_floor_f32_e32 v1, v0
+; GFX11-NEXT: s_delay_alu instid0(VALU_DEP_1) | instskip(NEXT) | instid1(VALU_DEP_1)
+; GFX11-NEXT: v_sub_f32_e32 v0, v0, v1
+; GFX11-NEXT: v_min_f32_e32 v0, 0x3f7fffff, v0
; GFX11-NEXT: s_setpc_b64 s[30:31]
+;
; GFX12-LABEL: basic_fract_f32_nonans:
; GFX12: ; %bb.0: ; %entry
; GFX12-NEXT: s_wait_loadcnt_dscnt 0x0
@@ -745,7 +761,10 @@ define float @basic_fract_f32_nonans(float nofpclass(nan) %x) {
; GFX12-NEXT: s_wait_samplecnt 0x0
; GFX12-NEXT: s_wait_bvhcnt 0x0
; GFX12-NEXT: s_wait_kmcnt 0x0
-; GFX12-NEXT: v_fract_f32_e32 v0, v0
+; GFX12-NEXT: v_floor_f32_e32 v1, v0
+; GFX12-NEXT: s_delay_alu instid0(VALU_DEP_1) | instskip(NEXT) | instid1(VALU_DEP_1)
+; GFX12-NEXT: v_sub_f32_e32 v0, v0, v1
+; GFX12-NEXT: v_min_num_f32_e32 v0, 0x3f7fffff, v0
; GFX12-NEXT: s_setpc_b64 s[30:31]
entry:
%floor = tail call float @llvm.floor.f32(float %x)
@@ -812,19 +831,13 @@ entry:
}
define float @basic_fract_f32_flags_fsub(float nofpclass(nan) %x) {
-; GFX6-IR-LABEL: define float @basic_fract_f32_flags_fsub(
-; GFX6-IR-SAME: float nofpclass(nan) [[X:%.*]]) {
-; GFX6-IR-NEXT: [[ENTRY:.*:]]
-; GFX6-IR-NEXT: [[FLOOR:%.*]] = tail call float @llvm.floor.f32(float [[X]])
-; GFX6-IR-NEXT: [[SUB:%.*]] = fsub nsz float [[X]], [[FLOOR]]
-; GFX6-IR-NEXT: [[MIN:%.*]] = tail call float @llvm.minnum.f32(float [[SUB]], float f0x3F7FFFFF)
-; GFX6-IR-NEXT: ret float [[MIN]]
-;
-; IR-FRACT-LABEL: define float @basic_fract_f32_flags_fsub(
-; IR-FRACT-SAME: float nofpclass(nan) [[X:%.*]]) {
-; IR-FRACT-NEXT: [[ENTRY:.*:]]
-; IR-FRACT-NEXT: [[MIN:%.*]] = call nnan float @llvm.amdgcn.fract.f32(float [[X]])
-; IR-FRACT-NEXT: ret float [[MIN]]
+; IR-LABEL: define float @basic_fract_f32_flags_fsub(
+; IR-SAME: float nofpclass(nan) [[X:%.*]]) {
+; IR-NEXT: [[ENTRY:.*:]]
+; IR-NEXT: [[FLOOR:%.*]] = tail call float @llvm.floor.f32(float [[X]])
+; IR-NEXT: [[SUB:%.*]] = fsub nsz float [[X]], [[FLOOR]]
+; IR-NEXT: [[MIN:%.*]] = tail call float @llvm.minnum.f32(float [[SUB]], float f0x3F7FFFFF)
+; IR-NEXT: ret float [[MIN]]
;
; GFX6-LABEL: basic_fract_f32_flags_fsub:
; GFX6: ; %bb.0: ; %entry
@@ -833,21 +846,32 @@ define float @basic_fract_f32_flags_fsub(float nofpclass(nan) %x) {
; GFX6-NEXT: v_sub_f32_e32 v0, v0, v1
; GFX6-NEXT: v_min_f32_e32 v0, 0x3f7fffff, v0
; GFX6-NEXT: s_setpc_b64 s[30:31]
+;
; GFX7-LABEL: basic_fract_f32_flags_fsub:
; GFX7: ; %bb.0: ; %entry
; GFX7-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX7-NEXT: v_fract_f32_e32 v0, v0
+; GFX7-NEXT: v_floor_f32_e32 v1, v0
+; GFX7-NEXT: v_sub_f32_e32 v0, v0, v1
+; GFX7-NEXT: v_min_f32_e32 v0, 0x3f7fffff, v0
; GFX7-NEXT: s_setpc_b64 s[30:31]
+;
; GFX8-LABEL: basic_fract_f32_flags_fsub:
; GFX8: ; %bb.0: ; %entry
; GFX8-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX8-NEXT: v_fract_f32_e32 v0, v0
+; GFX8-NEXT: v_floor_f32_e32 v1, v0
+; GFX8-NEXT: v_sub_f32_e32 v0, v0, v1
+; GFX8-NEXT: v_min_f32_e32 v0, 0x3f7fffff, v0
; GFX8-NEXT: s_setpc_b64 s[30:31]
+;
; GFX11-LABEL: basic_fract_f32_flags_fsub:
; GFX11: ; %bb.0: ; %entry
; GFX11-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX11-NEXT: v_fract_f32_e32 v0, v0
+; GFX11-NEXT: v_floor_f32_e32 v1, v0
+; GFX11-NEXT: s_delay_alu instid0(VALU_DEP_1) | instskip(NEXT) | instid1(VALU_DEP_1)
+; GFX11-NEXT: v_sub_f32_e32 v0, v0, v1
+; GFX11-NEXT: v_min_f32_e32 v0, 0x3f7fffff, v0
; GFX11-NEXT: s_setpc_b64 s[30:31]
+;
; GFX12-LABEL: basic_fract_f32_flags_fsub:
; GFX12: ; %bb.0: ; %entry
; GFX12-NEXT: s_wait_loadcnt_dscnt 0x0
@@ -855,7 +879,10 @@ define float @basic_fract_f32_flags_fsub(float nofpclass(nan) %x) {
; GFX12-NEXT: s_wait_samplecnt 0x0
; GFX12-NEXT: s_wait_bvhcnt 0x0
; GFX12-NEXT: s_wait_kmcnt 0x0
-; GFX12-NEXT: v_fract_f32_e32 v0, v0
+; GFX12-NEXT: v_floor_f32_e32 v1, v0
+; GFX12-NEXT: s_delay_alu instid0(VALU_DEP_1) | instskip(NEXT) | instid1(VALU_DEP_1)
+; GFX12-NEXT: v_sub_f32_e32 v0, v0, v1
+; GFX12-NEXT: v_min_num_f32_e32 v0, 0x3f7fffff, v0
; GFX12-NEXT: s_setpc_b64 s[30:31]
entry:
%floor = tail call float @llvm.floor.f32(float %x)
@@ -865,24 +892,13 @@ entry:
}
define <2 x float> @basic_fract_v2f32_nonans(<2 x float> nofpclass(nan) %x) {
-; GFX6-IR-LABEL: define <2 x float> @basic_fract_v2f32_nonans(
-; GFX6-IR-SAME: <2 x float> nofpclass(nan) [[X:%.*]]) {
-; GFX6-IR-NEXT: [[ENTRY:.*:]]
-; GFX6-IR-NEXT: [[FLOOR:%.*]] = tail call <2 x float> @llvm.floor.v2f32(<2 x float> [[X]])
-; GFX6-IR-NEXT: [[SUB:%.*]] = fsub <2 x float> [[X]], [[FLOOR]]
-; GFX6-IR-NEXT: [[MIN:%.*]] = tail call <2 x float> @llvm.minnum.v2f32(<2 x float> [[SUB]], <2 x float> splat (float f0x3F7FFFFF))
-; GFX6-IR-NEXT: ret <2 x float> [[MIN]]
-;
-; IR-FRACT-LABEL: define <2 x float> @basic_fract_v2f32_nonans(
-; IR-FRACT-SAME: <2 x float> nofpclass(nan) [[X:%.*]]) {
-; IR-FRACT-NEXT: [[ENTRY:.*:]]
-; IR-FRACT-NEXT: [[TMP0:%.*]] = extractelement <2 x float> [[X]], i64 0
-; IR-FRACT-NEXT: [[TMP1:%.*]] = extractelement <2 x float> [[X]], i64 1
-; IR-FRACT-NEXT: [[TMP2:%.*]] = call nnan float @llvm.amdgcn.fract.f32(float [[TMP0]])
-; IR-FRACT-NEXT: [[TMP3:%.*]] = call nnan float @llvm.amdgcn.fract.f32(float [[TMP1]])
-; IR-FRACT-NEXT: [[TMP4:%.*]] = insertelement <2 x float> poison, float [[TMP2]], i64 0
-; IR-FRACT-NEXT: [[MIN:%.*]] = insertelement <2 x float> [[TMP4]], float [[TMP3]], i64 1
-; IR-FRACT-NEXT: ret <2 x float> [[MIN]]
+; IR-LABEL: define <2 x float> @basic_fract_v2f32_nonans(
+; IR-SAME: <2 x float> nofpclass(nan) [[X:%.*]]) {
+; IR-NEXT: [[ENTRY:.*:]]
+; IR-NEXT: [[FLOOR:%.*]] = tail call <2 x float> @llvm.floor.v2f32(<2 x float> [[X]])
+; IR-NEXT: [[SUB:%.*]] = fsub <2 x float> [[X]], [[FLOOR]]
+; IR-NEXT: [[MIN:%.*]] = tail call <2 x float> @llvm.minnum.v2f32(<2 x float> [[SUB]], <2 x float> splat (float f0x3F7FFFFF))
+; IR-NEXT: ret <2 x float> [[MIN]]
;
; GFX6-LABEL: basic_fract_v2f32_nonans:
; GFX6: ; %bb.0: ; %entry
@@ -894,24 +910,39 @@ define <2 x float> @basic_fract_v2f32_nonans(<2 x float> nofpclass(nan) %x) {
; GFX6-NEXT: v_min_f32_e32 v0, 0x3f7fffff, v0
; GFX6-NEXT: v_min_f32_e32 v1, 0x3f7fffff, v1
; GFX6-NEXT: s_setpc_b64 s[30:31]
+;
; GFX7-LABEL: basic_fract_v2f32_nonans:
; GFX7: ; %bb.0: ; %entry
; GFX7-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX7-NEXT: v_fract_f32_e32 v0, v0
-; GFX7-NEXT: v_fract_f32_e32 v1, v1
+; GFX7-NEXT: v_floor_f32_e32 v2, v0
+; GFX7-NEXT: v_floor_f32_e32 v3, v1
+; GFX7-NEXT: v_sub_f32_e32 v1, v1, v3
+; GFX7-NEXT: v_sub_f32_e32 v0, v0, v2
+; GFX7-NEXT: v_min_f32_e32 v0, 0x3f7fffff, v0
+; GFX7-NEXT: v_min_f32_e32 v1, 0x3f7fffff, v1
; GFX7-NEXT: s_setpc_b64 s[30:31]
+;
; GFX8-LABEL: basic_fract_v2f32_nonans:
; GFX8: ; %bb.0: ; %entry
; GFX8-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX8-NEXT: v_fract_f32_e32 v0, v0
-; GFX8-NEXT: v_fract_f32_e32 v1, v1
+; GFX8-NEXT: v_floor_f32_e32 v2, v0
+; GFX8-NEXT: v_floor_f32_e32 v3, v1
+; GFX8-NEXT: v_sub_f32_e32 v1, v1, v3
+; GFX8-NEXT: v_sub_f32_e32 v0, v0, v2
+; GFX8-NEXT: v_min_f32_e32 v0, 0x3f7fffff, v0
+; GFX8-NEXT: v_min_f32_e32 v1, 0x3f7fffff, v1
; GFX8-NEXT: s_setpc_b64 s[30:31]
+;
; GFX11-LABEL: basic_fract_v2f32_nonans:
; GFX11: ; %bb.0: ; %entry
; GFX11-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX11-NEXT: v_fract_f32_e32 v0, v0
-; GFX11-NEXT: v_fract_f32_e32 v1, v1
+; GFX11-NEXT: v_floor_f32_e32 v2, v0
+; GFX11-NEXT: v_floor_f32_e32 v3, v1
+; GFX11-NEXT: s_delay_alu instid0(VALU_DEP_1) | instskip(NEXT) | instid1(VALU_DEP_1)
+; GFX11-NEXT: v_dual_sub_f32 v0, v0, v2 :: v_dual_sub_f32 v1, v1, v3
+; GFX11-NEXT: v_dual_min_f32 v0, 0x3f7fffff, v0 :: v_dual_min_f32 v1, 0x3f7fffff, v1
; GFX11-NEXT: s_setpc_b64 s[30:31]
+;
; GFX12-LABEL: basic_fract_v2f32_nonans:
; GFX12: ; %bb.0: ; %entry
; GFX12-NEXT: s_wait_loadcnt_dscnt 0x0
@@ -919,8 +950,11 @@ define <2 x float> @basic_fract_v2f32_nonans(<2 x float> nofpclass(nan) %x) {
; GFX12-NEXT: s_wait_samplecnt 0x0
; GFX12-NEXT: s_wait_bvhcnt 0x0
; GFX12-NEXT: s_wait_kmcnt 0x0
-; GFX12-NEXT: v_fract_f32_e32 v0, v0
-; GFX12-NEXT: v_fract_f32_e32 v1, v1
+; GFX12-NEXT: v_floor_f32_e32 v2, v0
+; GFX12-NEXT: v_floor_f32_e32 v3, v1
+; GFX12-NEXT: s_delay_alu instid0(VALU_DEP_1) | instskip(NEXT) | instid1(VALU_DEP_1)
+; GFX12-NEXT: v_dual_sub_f32 v0, v0, v2 :: v_dual_sub_f32 v1, v1, v3
+; GFX12-NEXT: v_dual_min_num_f32 v0, 0x3f7fffff, v0 :: v_dual_min_num_f32 v1, 0x3f7fffff, v1
; GFX12-NEXT: s_setpc_b64 s[30:31]
entry:
%floor = tail call <2 x float> @llvm.floor.v2f32(<2 x float> %x)
@@ -930,23 +964,14 @@ entry:
}
define float @basic_fract_f32_multi_use_fsub_nonans(float nofpclass(nan) %x, ptr addrspace(1) %ptr) {
-; GFX6-IR-LABEL: define float @basic_fract_f32_multi_use_fsub_nonans(
-; GFX6-IR-SAME: float nofpclass(nan) [[X:%.*]], ptr addrspace(1) [[PTR:%.*]]) {
-; GFX6-IR-NEXT: [[ENTRY:.*:]]
-; GFX6-IR-NEXT: [[FLOOR:%.*]] = tail call float @llvm.floor.f32(float [[X]])
-; GFX6-IR-NEXT: [[SUB:%.*]] = fsub float [[X]], [[FLOOR]]
-; GFX6-IR-NEXT: [[MIN:%.*]] = tail call float @llvm.minnum.f32(float [[SUB]], float f0x3F7FFFFF)
-; GFX6-IR-NEXT: store float [[SUB]], ptr addrspace(1) [[PTR]], align 4
-; GFX6-IR-NEXT: ret float [[MIN]]
-;
-; IR-FRACT-LABEL: define float @basic_fract_f32_multi_use_fsub_nonans(
-; IR-FRACT-SAME: float nofpclass(nan) [[X:%.*]], ptr addrspace(1) [[PTR:%.*]]) {
-; IR-FRACT-NEXT: [[ENTRY:.*:]]
-; IR-FRACT-NEXT: [[FLOOR:%.*]] = tail call float @llvm.floor.f32(float [[X]])
-; IR-FRACT-NEXT: [[SUB:%.*]] = fsub float [[X]], [[FLOOR]]
-; IR-FRACT-NEXT: [[MIN:%.*]] = call nnan float @llvm.amdgcn.fract.f32(float [[X]])
-; IR-FRACT-NEXT: store float [[SUB]], ptr addrspace(1) [[PTR]], align 4
-; IR-FRACT-NEXT: ret float [[MIN]]
+; IR-LABEL: define float @basic_fract_f32_multi_use_fsub_nonans(
+; IR-SAME: float nofpclass(nan) [[X:%.*]], ptr addrspace(1) [[PTR:%.*]]) {
+; IR-NEXT: [[ENTRY:.*:]]
+; IR-NEXT: [[FLOOR:%.*]] = tail call float @llvm.floor.f32(float [[X]])
+; IR-NEXT: [[SUB:%.*]] = fsub float [[X]], [[FLOOR]]
+; IR-NEXT: [[MIN:%.*]] = tail call float @llvm.minnum.f32(float [[SUB]], float f0x3F7FFFFF)
+; IR-NEXT: store float [[SUB]], ptr addrspace(1) [[PTR]], align 4
+; IR-NEXT: ret float [[MIN]]
;
; GFX6-LABEL: basic_fract_f32_multi_use_fsub_nonans:
; GFX6: ; %bb.0: ; %entry
@@ -961,37 +986,41 @@ define float @basic_fract_f32_multi_use_fsub_nonans(float nofpclass(nan) %x, ptr
; GFX6-NEXT: buffer_store_dword v3, v[1:2], s[4:7], 0 addr64
; GFX6-NEXT: s_waitcnt vmcnt(0) expcnt(0)
; GFX6-NEXT: s_setpc_b64 s[30:31]
+;
; GFX7-LABEL: basic_fract_f32_multi_use_fsub_nonans:
; GFX7: ; %bb.0: ; %entry
; GFX7-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX7-NEXT: s_mov_b32 s6, 0
; GFX7-NEXT: v_floor_f32_e32 v3, v0
+; GFX7-NEXT: s_mov_b32 s6, 0
+; GFX7-NEXT: v_sub_f32_e32 v3, v0, v3
; GFX7-NEXT: s_mov_b32 s7, 0xf000
; GFX7-NEXT: s_mov_b32 s4, s6
; GFX7-NEXT: s_mov_b32 s5, s6
-; GFX7-NEXT: v_sub_f32_e32 v3, v0, v3
-; GFX7-NEXT: v_fract_f32_e32 v0, v0
+; GFX7-NEXT: v_min_f32_e32 v0, 0x3f7fffff, v3
; GFX7-NEXT: buffer_store_dword v3, v[1:2], s[4:7], 0 addr64
; GFX7-NEXT: s_waitcnt vmcnt(0)
; GFX7-NEXT: s_setpc_b64 s[30:31]
+;
; GFX8-LABEL: basic_fract_f32_multi_use_fsub_nonans:
; GFX8: ; %bb.0: ; %entry
; GFX8-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
; GFX8-NEXT: v_floor_f32_e32 v3, v0
; GFX8-NEXT: v_sub_f32_e32 v3, v0, v3
-; GFX8-NEXT: v_fract_f32_e32 v0, v0
+; GFX8-NEXT: v_min_f32_e32 v0, 0x3f7fffff, v3
; GFX8-NEXT: global_store_dword v[1:2], v3, off
; GFX8-NEXT: s_waitcnt vmcnt(0)
; GFX8-NEXT: s_setpc_b64 s[30:31]
+;
; GFX11-LABEL: basic_fract_f32_multi_use_fsub_nonans:
; GFX11: ; %bb.0: ; %entry
; GFX11-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
; GFX11-NEXT: v_floor_f32_e32 v3, v0
-; GFX11-NEXT: s_delay_alu instid0(VALU_DEP_1)
+; GFX11-NEXT: s_delay_alu instid0(VALU_DEP_1) | instskip(NEXT) | instid1(VALU_DEP_1)
; GFX11-NEXT: v_sub_f32_e32 v3, v0, v3
-; GFX11-NEXT: v_fract_f32_e32 v0, v0
+; GFX11-NEXT: v_min_f32_e32 v0, 0x3f7fffff, v3
; GFX11-NEXT: global_store_b32 v[1:2], v3, off
; GFX11-NEXT: s_setpc_b64 s[30:31]
+;
; GFX12-LABEL: basic_fract_f32_multi_use_fsub_nonans:
; GFX12: ; %bb.0: ; %entry
; GFX12-NEXT: s_wait_loadcnt_dscnt 0x0
@@ -1000,9 +1029,9 @@ define float @basic_fract_f32_multi_use_fsub_nonans(float nofpclass(nan) %x, ptr
; GFX12-NEXT: s_wait_bvhcnt 0x0
; GFX12-NEXT: s_wait_kmcnt 0x0
; GFX12-NEXT: v_floor_f32_e32 v3, v0
-; GFX12-NEXT: s_delay_alu instid0(VALU_DEP_1)
+; GFX12-NEXT: s_delay_alu instid0(VALU_DEP_1) | instskip(NEXT) | instid1(VALU_DEP_1)
; GFX12-NEXT: v_sub_f32_e32 v3, v0, v3
-; GFX12-NEXT: v_fract_f32_e32 v0, v0
+; GFX12-NEXT: v_min_num_f32_e32 v0, 0x3f7fffff, v3
; GFX12-NEXT: global_store_b32 v[1:2], v3, off
; GFX12-NEXT: s_setpc_b64 s[30:31]
entry:
@@ -1183,19 +1212,13 @@ entry:
}
define float @nnan_src_fract_f32(float nofpclass(nan) %x) {
-; GFX6-IR-LABEL: define float @nnan_src_fract_f32(
-; GFX6-IR-SAME: float nofpclass(nan) [[X:%.*]]) {
-; GFX6-IR-NEXT: [[ENTRY:.*:]]
-; GFX6-IR-NEXT: [[FLOOR:%.*]] = tail call float @llvm.floor.f32(float [[X]])
-; GFX6-IR-NEXT: [[SUB:%.*]] = fsub float [[X]], [[FLOOR]]
-; GFX6-IR-NEXT: [[MIN:%.*]] = tail call float @llvm.minnum.f32(float [[SUB]], float f0x3F7FFFFF)
-; GFX6-IR-NEXT: ret float [[MIN]]
-;
-; IR-FRACT-LABEL: define float @nnan_src_fract_f32(
-; IR-FRACT-SAME: float nofpclass(nan) [[X:%.*]]) {
-; IR-FRACT-NEXT: [[ENTRY:.*:]]
-; IR-FRACT-NEXT: [[MIN:%.*]] = call nnan float @llvm.amdgcn.fract.f32(float [[X]])
-; IR-FRACT-NEXT: ret float [[MIN]]
+; IR-LABEL: define float @nnan_src_fract_f32(
+; IR-SAME: float nofpclass(nan) [[X:%.*]]) {
+; IR-NEXT: [[ENTRY:.*:]]
+; IR-NEXT: [[FLOOR:%.*]] = tail call float @llvm.floor.f32(float [[X]])
+; IR-NEXT: [[SUB:%.*]] = fsub float [[X]], [[FLOOR]]
+; IR-NEXT: [[MIN:%.*]] = tail call float @llvm.minnum.f32(float [[SUB]], float f0x3F7FFFFF)
+; IR-NEXT: ret float [[MIN]]
;
; GFX6-LABEL: nnan_src_fract_f32:
; GFX6: ; %bb.0: ; %entry
@@ -1204,21 +1227,32 @@ define float @nnan_src_fract_f32(float nofpclass(nan) %x) {
; GFX6-NEXT: v_sub_f32_e32 v0, v0, v1
; GFX6-NEXT: v_min_f32_e32 v0, 0x3f7fffff, v0
; GFX6-NEXT: s_setpc_b64 s[30:31]
+;
; GFX7-LABEL: nnan_src_fract_f32:
; GFX7: ; %bb.0: ; %entry
; GFX7-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX7-NEXT: v_fract_f32_e32 v0, v0
+; GFX7-NEXT: v_floor_f32_e32 v1, v0
+; GFX7-NEXT: v_sub_f32_e32 v0, v0, v1
+; GFX7-NEXT: v_min_f32_e32 v0, 0x3f7fffff, v0
; GFX7-NEXT: s_setpc_b64 s[30:31]
+;
; GFX8-LABEL: nnan_src_fract_f32:
; GFX8: ; %bb.0: ; %entry
; GFX8-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX8-NEXT: v_fract_f32_e32 v0, v0
+; GFX8-NEXT: v_floor_f32_e32 v1, v0
+; GFX8-NEXT: v_sub_f32_e32 v0, v0, v1
+; GFX8-NEXT: v_min_f32_e32 v0, 0x3f7fffff, v0
; GFX8-NEXT: s_setpc_b64 s[30:31]
+;
; GFX11-LABEL: nnan_src_fract_f32:
; GFX11: ; %bb.0: ; %entry
; GFX11-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX11-NEXT: v_fract_f32_e32 v0, v0
+; GFX11-NEXT: v_floor_f32_e32 v1, v0
+; GFX11-NEXT: s_delay_alu instid0(VALU_DEP_1) | instskip(NEXT) | instid1(VALU_DEP_1)
+; GFX11-NEXT: v_sub_f32_e32 v0, v0, v1
+; GFX11-NEXT: v_min_f32_e32 v0, 0x3f7fffff, v0
; GFX11-NEXT: s_setpc_b64 s[30:31]
+;
; GFX12-LABEL: nnan_src_fract_f32:
; GFX12: ; %bb.0: ; %entry
; GFX12-NEXT: s_wait_loadcnt_dscnt 0x0
@@ -1226,7 +1260,10 @@ define float @nnan_src_fract_f32(float nofpclass(nan) %x) {
; GFX12-NEXT: s_wait_samplecnt 0x0
; GFX12-NEXT: s_wait_bvhcnt 0x0
; GFX12-NEXT: s_wait_kmcnt 0x0
-; GFX12-NEXT: v_fract_f32_e32 v0, v0
+; GFX12-NEXT: v_floor_f32_e32 v1, v0
+; GFX12-NEXT: s_delay_alu instid0(VALU_DEP_1) | instskip(NEXT) | instid1(VALU_DEP_1)
+; GFX12-NEXT: v_sub_f32_e32 v0, v0, v1
+; GFX12-NEXT: v_min_num_f32_e32 v0, 0x3f7fffff, v0
; GFX12-NEXT: s_setpc_b64 s[30:31]
entry:
%floor = tail call float @llvm.floor.f32(float %x)
@@ -1235,46 +1272,49 @@ entry:
ret float %min
}
-; Negative test
-define float @not_fract_f32_wrong_const(float nofpclass(nan) %x) {
-; IR-LABEL: define float @not_fract_f32_wrong_const(
+define float @ninf_minnum_fract_f32_nonans(float nofpclass(nan) %x) {
+; IR-LABEL: define float @ninf_minnum_fract_f32_nonans(
; IR-SAME: float nofpclass(nan) [[X:%.*]]) {
; IR-NEXT: [[ENTRY:.*:]]
; IR-NEXT: [[FLOOR:%.*]] = tail call float @llvm.floor.f32(float [[X]])
; IR-NEXT: [[SUB:%.*]] = fsub float [[X]], [[FLOOR]]
-; IR-NEXT: [[MIN:%.*]] = tail call float @llvm.minnum.f32(float [[SUB]], float f0x3F7FFFFE)
+; IR-NEXT: [[MIN:%.*]] = tail call ninf float @llvm.minnum.f32(float [[SUB]], float f0x3F7FFFFF)
; IR-NEXT: ret float [[MIN]]
;
-; GFX6-LABEL: not_fract_f32_wrong_const:
+; GFX6-LABEL: ninf_minnum_fract_f32_nonans:
; GFX6: ; %bb.0: ; %entry
; GFX6-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
; GFX6-NEXT: v_floor_f32_e32 v1, v0
; GFX6-NEXT: v_sub_f32_e32 v0, v0, v1
-; GFX6-NEXT: v_min_f32_e32 v0, 0x3f7ffffe, v0
+; GFX6-NEXT: v_min_f32_e32 v0, 0x3f7fffff, v0
; GFX6-NEXT: s_setpc_b64 s[30:31]
-; GFX7-LABEL: not_fract_f32_wrong_const:
+;
+; GFX7-LABEL: ninf_minnum_fract_f32_nonans:
; GFX7: ; %bb.0: ; %entry
; GFX7-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
; GFX7-NEXT: v_floor_f32_e32 v1, v0
; GFX7-NEXT: v_sub_f32_e32 v0, v0, v1
-; GFX7-NEXT: v_min_f32_e32 v0, 0x3f7ffffe, v0
+; GFX7-NEXT: v_min_f32_e32 v0, 0x3f7fffff, v0
; GFX7-NEXT: s_setpc_b64 s[30:31]
-; GFX8-LABEL: not_fract_f32_wrong_const:
+;
+; GFX8-LABEL: ninf_minnum_fract_f32_nonans:
; GFX8: ; %bb.0: ; %entry
; GFX8-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
; GFX8-NEXT: v_floor_f32_e32 v1, v0
; GFX8-NEXT: v_sub_f32_e32 v0, v0, v1
-; GFX8-NEXT: v_min_f32_e32 v0, 0x3f7ffffe, v0
+; GFX8-NEXT: v_min_f32_e32 v0, 0x3f7fffff, v0
; GFX8-NEXT: s_setpc_b64 s[30:31]
-; GFX11-LABEL: not_fract_f32_wrong_const:
+;
+; GFX11-LABEL: ninf_minnum_fract_f32_nonans:
; GFX11: ; %bb.0: ; %entry
; GFX11-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
; GFX11-NEXT: v_floor_f32_e32 v1, v0
; GFX11-NEXT: s_delay_alu instid0(VALU_DEP_1) | instskip(NEXT) | instid1(VALU_DEP_1)
; GFX11-NEXT: v_sub_f32_e32 v0, v0, v1
-; GFX11-NEXT: v_min_f32_e32 v0, 0x3f7ffffe, v0
+; GFX11-NEXT: v_min_f32_e32 v0, 0x3f7fffff, v0
; GFX11-NEXT: s_setpc_b64 s[30:31]
-; GFX12-LABEL: not_fract_f32_wrong_const:
+;
+; GFX12-LABEL: ninf_minnum_fract_f32_nonans:
; GFX12: ; %bb.0: ; %entry
; GFX12-NEXT: s_wait_loadcnt_dscnt 0x0
; GFX12-NEXT: s_wait_expcnt 0x0
@@ -1284,7 +1324,236 @@ define float @not_fract_f32_wrong_const(float nofpclass(nan) %x) {
; GFX12-NEXT: v_floor_f32_e32 v1, v0
; GFX12-NEXT: s_delay_alu instid0(VALU_DEP_1) | instskip(NEXT) | instid1(VALU_DEP_1)
; GFX12-NEXT: v_sub_f32_e32 v0, v0, v1
-; GFX12-NEXT: v_min_num_f32_e32 v0, 0x3f7ffffe, v0
+; GFX12-NEXT: v_min_num_f32_e32 v0, 0x3f7fffff, v0
+; GFX12-NEXT: s_setpc_b64 s[30:31]
+entry:
+ %floor = tail call float @llvm.floor.f32(float %x)
+ %sub = fsub float %x, %floor
+ %min = tail call ninf float @llvm.minnum.f32(float %sub, float 0x3FEFFFFFE0000000)
+ ret float %min
+}
+
+define float @ninf_fsub_fract_f32_nonans(float nofpclass(nan) %x) {
+; GFX6-IR-LABEL: define float @ninf_fsub_fract_f32_nonans(
+; GFX6-IR-SAME: float nofpclass(nan) [[X:%.*]]) {
+; GFX6-IR-NEXT: [[ENTRY:.*:]]
+; GFX6-IR-NEXT: [[FLOOR:%.*]] = tail call float @llvm.floor.f32(float [[X]])
+; GFX6-IR-NEXT: [[SUB:%.*]] = fsub ninf float [[X]], [[FLOOR]]
+; GFX6-IR-NEXT: [[MIN:%.*]] = tail call float @llvm.minnum.f32(float [[SUB]], float f0x3F7FFFFF)
+; GFX6-IR-NEXT: ret float [[MIN]]
+;
+; IR-FRACT-LABEL: define float @ninf_fsub_fract_f32_nonans(
+; IR-FRACT-SAME: float nofpclass(nan) [[X:%.*]]) {
+; IR-FRACT-NEXT: [[ENTRY:.*:]]
+; IR-FRACT-NEXT: [[MIN:%.*]] = call nnan float @llvm.amdgcn.fract.f32(float [[X]])
+; IR-FRACT-NEXT: ret float [[MIN]]
+;
+; GFX6-LABEL: ninf_fsub_fract_f32_nonans:
+; GFX6: ; %bb.0: ; %entry
+; GFX6-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX6-NEXT: v_floor_f32_e32 v1, v0
+; GFX6-NEXT: v_sub_f32_e32 v0, v0, v1
+; GFX6-NEXT: v_min_f32_e32 v0, 0x3f7fffff, v0
+; GFX6-NEXT: s_setpc_b64 s[30:31]
+;
+; GFX7-LABEL: ninf_fsub_fract_f32_nonans:
+; GFX7: ; %bb.0: ; %entry
+; GFX7-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX7-NEXT: v_fract_f32_e32 v0, v0
+; GFX7-NEXT: s_setpc_b64 s[30:31]
+;
+; GFX8-LABEL: ninf_fsub_fract_f32_nonans:
+; GFX8: ; %bb.0: ; %entry
+; GFX8-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX8-NEXT: v_fract_f32_e32 v0, v0
+; GFX8-NEXT: s_setpc_b64 s[30:31]
+;
+; GFX11-LABEL: ninf_fsub_fract_f32_nonans:
+; GFX11: ; %bb.0: ; %entry
+; GFX11-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-NEXT: v_fract_f32_e32 v0, v0
+; GFX11-NEXT: s_setpc_b64 s[30:31]
+;
+; GFX12-LABEL: ninf_fsub_fract_f32_nonans:
+; GFX12: ; %bb.0: ; %entry
+; GFX12-NEXT: s_wait_loadcnt_dscnt 0x0
+; GFX12-NEXT: s_wait_expcnt 0x0
+; GFX12-NEXT: s_wait_samplecnt 0x0
+; GFX12-NEXT: s_wait_bvhcnt 0x0
+; GFX12-NEXT: s_wait_kmcnt 0x0
+; GFX12-NEXT: v_fract_f32_e32 v0, v0
+; GFX12-NEXT: s_setpc_b64 s[30:31]
+entry:
+ %floor = tail call float @llvm.floor.f32(float %x)
+ %sub = fsub ninf float %x, %floor
+ %min = tail call float @llvm.minnum.f32(float %sub, float 0x3FEFFFFFE0000000)
+ ret float %min
+}
+
+define float @nnan_fsub_fract_f32_nonans(float nofpclass(nan) %x) {
+; GFX6-IR-LABEL: define float @nnan_fsub_fract_f32_nonans(
+; GFX6-IR-SAME: float nofpclass(nan) [[X:%.*]]) {
+; GFX6-IR-NEXT: [[ENTRY:.*:]]
+; GFX6-IR-NEXT: [[FLOOR:%.*]] = tail call float @llvm.floor.f32(float [[X]])
+; GFX6-IR-NEXT: [[SUB:%.*]] = fsub nnan float [[X]], [[FLOOR]]
+; GFX6-IR-NEXT: [[MIN:%.*]] = tail call float @llvm.minnum.f32(float [[SUB]], float f0x3F7FFFFF)
+; GFX6-IR-NEXT: ret float [[MIN]]
+;
+; IR-FRACT-LABEL: define float @nnan_fsub_fract_f32_nonans(
+; IR-FRACT-SAME: float nofpclass(nan) [[X:%.*]]) {
+; IR-FRACT-NEXT: [[ENTRY:.*:]]
+; IR-FRACT-NEXT: [[MIN:%.*]] = call nnan float @llvm.amdgcn.fract.f32(float [[X]])
+; IR-FRACT-NEXT: ret float [[MIN]]
+;
+; GFX6-LABEL: nnan_fsub_fract_f32_nonans:
+; GFX6: ; %bb.0: ; %entry
+; GFX6-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX6-NEXT: v_floor_f32_e32 v1, v0
+; GFX6-NEXT: v_sub_f32_e32 v0, v0, v1
+; GFX6-NEXT: v_min_f32_e32 v0, 0x3f7fffff, v0
+; GFX6-NEXT: s_setpc_b64 s[30:31]
+;
+; GFX7-LABEL: nnan_fsub_fract_f32_nonans:
+; GFX7: ; %bb.0: ; %entry
+; GFX7-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX7-NEXT: v_fract_f32_e32 v0, v0
+; GFX7-NEXT: s_setpc_b64 s[30:31]
+;
+; GFX8-LABEL: nnan_fsub_fract_f32_nonans:
+; GFX8: ; %bb.0: ; %entry
+; GFX8-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX8-NEXT: v_fract_f32_e32 v0, v0
+; GFX8-NEXT: s_setpc_b64 s[30:31]
+;
+; GFX11-LABEL: nnan_fsub_fract_f32_nonans:
+; GFX11: ; %bb.0: ; %entry
+; GFX11-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-NEXT: v_fract_f32_e32 v0, v0
+; GFX11-NEXT: s_setpc_b64 s[30:31]
+;
+; GFX12-LABEL: nnan_fsub_fract_f32_nonans:
+; GFX12: ; %bb.0: ; %entry
+; GFX12-NEXT: s_wait_loadcnt_dscnt 0x0
+; GFX12-NEXT: s_wait_expcnt 0x0
+; GFX12-NEXT: s_wait_samplecnt 0x0
+; GFX12-NEXT: s_wait_bvhcnt 0x0
+; GFX12-NEXT: s_wait_kmcnt 0x0
+; GFX12-NEXT: v_fract_f32_e32 v0, v0
+; GFX12-NEXT: s_setpc_b64 s[30:31]
+entry:
+ %floor = tail call float @llvm.floor.f32(float %x)
+ %sub = fsub nnan float %x, %floor
+ %min = tail call float @llvm.minnum.f32(float %sub, float 0x3FEFFFFFE0000000)
+ ret float %min
+}
+
+define float @basic_fract_f32_nofpclass_nan_inf(float nofpclass(nan inf) %x) {
+; GFX6-IR-LABEL: define float @basic_fract_f32_nofpclass_nan_inf(
+; GFX6-IR-SAME: float nofpclass(nan inf) [[X:%.*]]) {
+; GFX6-IR-NEXT: [[ENTRY:.*:]]
+; GFX6-IR-NEXT: [[FLOOR:%.*]] = tail call float @llvm.floor.f32(float [[X]])
+; GFX6-IR-NEXT: [[SUB:%.*]] = fsub float [[X]], [[FLOOR]]
+; GFX6-IR-NEXT: [[MIN:%.*]] = tail call float @llvm.minnum.f32(float [[SUB]], float f0x3F7FFFFF)
+; GFX6-IR-NEXT: ret float [[MIN]]
+;
+; IR-FRACT-LABEL: define float @basic_fract_f32_nofpclass_nan_inf(
+; IR-FRACT-SAME: float nofpclass(nan inf) [[X:%.*]]) {
+; IR-FRACT-NEXT: [[ENTRY:.*:]]
+; IR-FRACT-NEXT: [[MIN:%.*]] = call nnan float @llvm.amdgcn.fract.f32(float [[X]])
+; IR-FRACT-NEXT: ret float [[MIN]]
+;
+; GFX6-LABEL: basic_fract_f32_nofpclass_nan_inf:
+; GFX6: ; %bb.0: ; %entry
+; GFX6-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX6-NEXT: v_floor_f32_e32 v1, v0
+; GFX6-NEXT: v_sub_f32_e32 v0, v0, v1
+; GFX6-NEXT: v_min_f32_e32 v0, 0x3f7fffff, v0
+; GFX6-NEXT: s_setpc_b64 s[30:31]
+;
+; GFX7-LABEL: basic_fract_f32_nofpclass_nan_inf:
+; GFX7: ; %bb.0: ; %entry
+; GFX7-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX7-NEXT: v_fract_f32_e32 v0, v0
+; GFX7-NEXT: s_setpc_b64 s[30:31]
+;
+; GFX8-LABEL: basic_fract_f32_nofpclass_nan_inf:
+; GFX8: ; %bb.0: ; %entry
+; GFX8-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX8-NEXT: v_fract_f32_e32 v0, v0
+; GFX8-NEXT: s_setpc_b64 s[30:31]
+;
+; GFX11-LABEL: basic_fract_f32_nofpclass_nan_inf:
+; GFX11: ; %bb.0: ; %entry
+; GFX11-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-NEXT: v_fract_f32_e32 v0, v0
+; GFX11-NEXT: s_setpc_b64 s[30:31]
+;
+; GFX12-LABEL: basic_fract_f32_nofpclass_nan_inf:
+; GFX12: ; %bb.0: ; %entry
+; GFX12-NEXT: s_wait_loadcnt_dscnt 0x0
+; GFX12-NEXT: s_wait_expcnt 0x0
+; GFX12-NEXT: s_wait_samplecnt 0x0
+; GFX12-NEXT: s_wait_bvhcnt 0x0
+; GFX12-NEXT: s_wait_kmcnt 0x0
+; GFX12-NEXT: v_fract_f32_e32 v0, v0
+; GFX12-NEXT: s_setpc_b64 s[30:31]
+entry:
+ %floor = tail call float @llvm.floor.f32(float %x)
+ %sub = fsub float %x, %floor
+ %min = tail call float @llvm.minnum.f32(float %sub, float 0x3FEFFFFFE0000000)
+ ret float %min
+}
+
+; Negative test
+define float @not_fract_f32_wrong_const(float nofpclass(nan) %x) {
+; IR-LABEL: define float @not_fract_f32_wrong_const(
+; IR-SAME: float nofpclass(nan) [[X:%.*]]) {
+; IR-NEXT: [[ENTRY:.*:]]
+; IR-NEXT: [[FLOOR:%.*]] = tail call float @llvm.floor.f32(float [[X]])
+; IR-NEXT: [[SUB:%.*]] = fsub float [[X]], [[FLOOR]]
+; IR-NEXT: [[MIN:%.*]] = tail call float @llvm.minnum.f32(float [[SUB]], float f0x3F7FFFFE)
+; IR-NEXT: ret float [[MIN]]
+;
+; GFX6-LABEL: not_fract_f32_wrong_const:
+; GFX6: ; %bb.0: ; %entry
+; GFX6-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX6-NEXT: v_floor_f32_e32 v1, v0
+; GFX6-NEXT: v_sub_f32_e32 v0, v0, v1
+; GFX6-NEXT: v_min_f32_e32 v0, 0x3f7ffffe, v0
+; GFX6-NEXT: s_setpc_b64 s[30:31]
+; GFX7-LABEL: not_fract_f32_wrong_const:
+; GFX7: ; %bb.0: ; %entry
+; GFX7-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX7-NEXT: v_floor_f32_e32 v1, v0
+; GFX7-NEXT: v_sub_f32_e32 v0, v0, v1
+; GFX7-NEXT: v_min_f32_e32 v0, 0x3f7ffffe, v0
+; GFX7-NEXT: s_setpc_b64 s[30:31]
+; GFX8-LABEL: not_fract_f32_wrong_const:
+; GFX8: ; %bb.0: ; %entry
+; GFX8-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX8-NEXT: v_floor_f32_e32 v1, v0
+; GFX8-NEXT: v_sub_f32_e32 v0, v0, v1
+; GFX8-NEXT: v_min_f32_e32 v0, 0x3f7ffffe, v0
+; GFX8-NEXT: s_setpc_b64 s[30:31]
+; GFX11-LABEL: not_fract_f32_wrong_const:
+; GFX11: ; %bb.0: ; %entry
+; GFX11-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-NEXT: v_floor_f32_e32 v1, v0
+; GFX11-NEXT: s_delay_alu instid0(VALU_DEP_1) | instskip(NEXT) | instid1(VALU_DEP_1)
+; GFX11-NEXT: v_sub_f32_e32 v0, v0, v1
+; GFX11-NEXT: v_min_f32_e32 v0, 0x3f7ffffe, v0
+; GFX11-NEXT: s_setpc_b64 s[30:31]
+; GFX12-LABEL: not_fract_f32_wrong_const:
+; GFX12: ; %bb.0: ; %entry
+; GFX12-NEXT: s_wait_loadcnt_dscnt 0x0
+; GFX12-NEXT: s_wait_expcnt 0x0
+; GFX12-NEXT: s_wait_samplecnt 0x0
+; GFX12-NEXT: s_wait_bvhcnt 0x0
+; GFX12-NEXT: s_wait_kmcnt 0x0
+; GFX12-NEXT: v_floor_f32_e32 v1, v0
+; GFX12-NEXT: s_delay_alu instid0(VALU_DEP_1) | instskip(NEXT) | instid1(VALU_DEP_1)
+; GFX12-NEXT: v_sub_f32_e32 v0, v0, v1
+; GFX12-NEXT: v_min_num_f32_e32 v0, 0x3f7ffffe, v0
; GFX12-NEXT: s_setpc_b64 s[30:31]
entry:
%floor = tail call float @llvm.floor.f32(float %x)
@@ -1559,21 +1828,15 @@ entry:
; No inf check
define float @select_nan_fract_f32(float %x) {
-; GFX6-IR-LABEL: define float @select_nan_fract_f32(
-; GFX6-IR-SAME: float [[X:%.*]]) {
-; GFX6-IR-NEXT: [[ENTRY:.*:]]
-; GFX6-IR-NEXT: [[FLOOR:%.*]] = tail call float @llvm.floor.f32(float [[X]])
-; GFX6-IR-NEXT: [[SUB:%.*]] = fsub float [[X]], [[FLOOR]]
-; GFX6-IR-NEXT: [[MIN:%.*]] = tail call float @llvm.minnum.f32(float [[SUB]], float f0x3F7FFFFF)
-; GFX6-IR-NEXT: [[UNO:%.*]] = fcmp uno float [[X]], 0.000000e+00
-; GFX6-IR-NEXT: [[COND:%.*]] = select i1 [[UNO]], float [[X]], float [[MIN]]
-; GFX6-IR-NEXT: ret float [[COND]]
-;
-; IR-FRACT-LABEL: define float @select_nan_fract_f32(
-; IR-FRACT-SAME: float [[X:%.*]]) {
-; IR-FRACT-NEXT: [[ENTRY:.*:]]
-; IR-FRACT-NEXT: [[COND:%.*]] = call float @llvm.amdgcn.fract.f32(float [[X]])
-; IR-FRACT-NEXT: ret float [[COND]]
+; IR-LABEL: define float @select_nan_fract_f32(
+; IR-SAME: float [[X:%.*]]) {
+; IR-NEXT: [[ENTRY:.*:]]
+; IR-NEXT: [[FLOOR:%.*]] = tail call float @llvm.floor.f32(float [[X]])
+; IR-NEXT: [[SUB:%.*]] = fsub float [[X]], [[FLOOR]]
+; IR-NEXT: [[MIN:%.*]] = tail call float @llvm.minnum.f32(float [[SUB]], float f0x3F7FFFFF)
+; IR-NEXT: [[UNO:%.*]] = fcmp uno float [[X]], 0.000000e+00
+; IR-NEXT: [[COND:%.*]] = select i1 [[UNO]], float [[X]], float [[MIN]]
+; IR-NEXT: ret float [[COND]]
;
; GFX6-LABEL: select_nan_fract_f32:
; GFX6: ; %bb.0: ; %entry
@@ -1584,21 +1847,39 @@ define float @select_nan_fract_f32(float %x) {
; GFX6-NEXT: v_cmp_u_f32_e32 vcc, v0, v0
; GFX6-NEXT: v_cndmask_b32_e32 v0, v1, v0, vcc
; GFX6-NEXT: s_setpc_b64 s[30:31]
+;
; GFX7-LABEL: select_nan_fract_f32:
; GFX7: ; %bb.0: ; %entry
; GFX7-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX7-NEXT: v_fract_f32_e32 v0, v0
+; GFX7-NEXT: v_floor_f32_e32 v1, v0
+; GFX7-NEXT: v_sub_f32_e32 v1, v0, v1
+; GFX7-NEXT: v_min_f32_e32 v1, 0x3f7fffff, v1
+; GFX7-NEXT: v_cmp_u_f32_e32 vcc, v0, v0
+; GFX7-NEXT: v_cndmask_b32_e32 v0, v1, v0, vcc
; GFX7-NEXT: s_setpc_b64 s[30:31]
+;
; GFX8-LABEL: select_nan_fract_f32:
; GFX8: ; %bb.0: ; %entry
; GFX8-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX8-NEXT: v_fract_f32_e32 v0, v0
+; GFX8-NEXT: v_floor_f32_e32 v1, v0
+; GFX8-NEXT: v_sub_f32_e32 v1, v0, v1
+; GFX8-NEXT: v_min_f32_e32 v1, 0x3f7fffff, v1
+; GFX8-NEXT: v_cmp_u_f32_e32 vcc, v0, v0
+; GFX8-NEXT: v_cndmask_b32_e32 v0, v1, v0, vcc
; GFX8-NEXT: s_setpc_b64 s[30:31]
+;
; GFX11-LABEL: select_nan_fract_f32:
; GFX11: ; %bb.0: ; %entry
; GFX11-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX11-NEXT: v_fract_f32_e32 v0, v0
+; GFX11-NEXT: v_floor_f32_e32 v1, v0
+; GFX11-NEXT: v_cmp_u_f32_e32 vcc_lo, v0, v0
+; GFX11-NEXT: s_delay_alu instid0(VALU_DEP_2) | instskip(NEXT) | instid1(VALU_DEP_1)
+; GFX11-NEXT: v_sub_f32_e32 v1, v0, v1
+; GFX11-NEXT: v_min_f32_e32 v1, 0x3f7fffff, v1
+; GFX11-NEXT: s_delay_alu instid0(VALU_DEP_1)
+; GFX11-NEXT: v_cndmask_b32_e32 v0, v1, v0, vcc_lo
; GFX11-NEXT: s_setpc_b64 s[30:31]
+;
; GFX12-LABEL: select_nan_fract_f32:
; GFX12: ; %bb.0: ; %entry
; GFX12-NEXT: s_wait_loadcnt_dscnt 0x0
@@ -1606,7 +1887,14 @@ define float @select_nan_fract_f32(float %x) {
; GFX12-NEXT: s_wait_samplecnt 0x0
; GFX12-NEXT: s_wait_bvhcnt 0x0
; GFX12-NEXT: s_wait_kmcnt 0x0
-; GFX12-NEXT: v_fract_f32_e32 v0, v0
+; GFX12-NEXT: v_floor_f32_e32 v1, v0
+; GFX12-NEXT: v_cmp_u_f32_e32 vcc_lo, v0, v0
+; GFX12-NEXT: s_delay_alu instid0(VALU_DEP_2) | instskip(NEXT) | instid1(VALU_DEP_1)
+; GFX12-NEXT: v_sub_f32_e32 v1, v0, v1
+; GFX12-NEXT: v_min_num_f32_e32 v1, 0x3f7fffff, v1
+; GFX12-NEXT: s_wait_alu depctr_va_vcc(0)
+; GFX12-NEXT: s_delay_alu instid0(VALU_DEP_1)
+; GFX12-NEXT: v_cndmask_b32_e32 v0, v1, v0, vcc_lo
; GFX12-NEXT: s_setpc_b64 s[30:31]
entry:
%floor = tail call float @llvm.floor.f32(float %x)
@@ -1618,21 +1906,15 @@ entry:
}
define float @commuted_select_nan_fract_f32(float %x) {
-; GFX6-IR-LABEL: define float @commuted_select_nan_fract_f32(
-; GFX6-IR-SAME: float [[X:%.*]]) {
-; GFX6-IR-NEXT: [[ENTRY:.*:]]
-; GFX6-IR-NEXT: [[FLOOR:%.*]] = tail call float @llvm.floor.f32(float [[X]])
-; GFX6-IR-NEXT: [[SUB:%.*]] = fsub float [[X]], [[FLOOR]]
-; GFX6-IR-NEXT: [[MIN:%.*]] = tail call float @llvm.minnum.f32(float [[SUB]], float f0x3F7FFFFF)
-; GFX6-IR-NEXT: [[UNO:%.*]] = fcmp ord float [[X]], 0.000000e+00
-; GFX6-IR-NEXT: [[COND:%.*]] = select i1 [[UNO]], float [[MIN]], float [[X]]
-; GFX6-IR-NEXT: ret float [[COND]]
-;
-; IR-FRACT-LABEL: define float @commuted_select_nan_fract_f32(
-; IR-FRACT-SAME: float [[X:%.*]]) {
-; IR-FRACT-NEXT: [[ENTRY:.*:]]
-; IR-FRACT-NEXT: [[COND:%.*]] = call float @llvm.amdgcn.fract.f32(float [[X]])
-; IR-FRACT-NEXT: ret float [[COND]]
+; IR-LABEL: define float @commuted_select_nan_fract_f32(
+; IR-SAME: float [[X:%.*]]) {
+; IR-NEXT: [[ENTRY:.*:]]
+; IR-NEXT: [[FLOOR:%.*]] = tail call float @llvm.floor.f32(float [[X]])
+; IR-NEXT: [[SUB:%.*]] = fsub float [[X]], [[FLOOR]]
+; IR-NEXT: [[MIN:%.*]] = tail call float @llvm.minnum.f32(float [[SUB]], float f0x3F7FFFFF)
+; IR-NEXT: [[UNO:%.*]] = fcmp ord float [[X]], 0.000000e+00
+; IR-NEXT: [[COND:%.*]] = select i1 [[UNO]], float [[MIN]], float [[X]]
+; IR-NEXT: ret float [[COND]]
;
; GFX6-LABEL: commuted_select_nan_fract_f32:
; GFX6: ; %bb.0: ; %entry
@@ -1643,21 +1925,39 @@ define float @commuted_select_nan_fract_f32(float %x) {
; GFX6-NEXT: v_cmp_o_f32_e32 vcc, v0, v0
; GFX6-NEXT: v_cndmask_b32_e32 v0, v0, v1, vcc
; GFX6-NEXT: s_setpc_b64 s[30:31]
+;
; GFX7-LABEL: commuted_select_nan_fract_f32:
; GFX7: ; %bb.0: ; %entry
; GFX7-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX7-NEXT: v_fract_f32_e32 v0, v0
+; GFX7-NEXT: v_floor_f32_e32 v1, v0
+; GFX7-NEXT: v_sub_f32_e32 v1, v0, v1
+; GFX7-NEXT: v_min_f32_e32 v1, 0x3f7fffff, v1
+; GFX7-NEXT: v_cmp_o_f32_e32 vcc, v0, v0
+; GFX7-NEXT: v_cndmask_b32_e32 v0, v0, v1, vcc
; GFX7-NEXT: s_setpc_b64 s[30:31]
+;
; GFX8-LABEL: commuted_select_nan_fract_f32:
; GFX8: ; %bb.0: ; %entry
; GFX8-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX8-NEXT: v_fract_f32_e32 v0, v0
+; GFX8-NEXT: v_floor_f32_e32 v1, v0
+; GFX8-NEXT: v_sub_f32_e32 v1, v0, v1
+; GFX8-NEXT: v_min_f32_e32 v1, 0x3f7fffff, v1
+; GFX8-NEXT: v_cmp_o_f32_e32 vcc, v0, v0
+; GFX8-NEXT: v_cndmask_b32_e32 v0, v0, v1, vcc
; GFX8-NEXT: s_setpc_b64 s[30:31]
+;
; GFX11-LABEL: commuted_select_nan_fract_f32:
; GFX11: ; %bb.0: ; %entry
; GFX11-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX11-NEXT: v_fract_f32_e32 v0, v0
+; GFX11-NEXT: v_floor_f32_e32 v1, v0
+; GFX11-NEXT: v_cmp_o_f32_e32 vcc_lo, v0, v0
+; GFX11-NEXT: s_delay_alu instid0(VALU_DEP_2) | instskip(NEXT) | instid1(VALU_DEP_1)
+; GFX11-NEXT: v_sub_f32_e32 v1, v0, v1
+; GFX11-NEXT: v_min_f32_e32 v1, 0x3f7fffff, v1
+; GFX11-NEXT: s_delay_alu instid0(VALU_DEP_1)
+; GFX11-NEXT: v_cndmask_b32_e32 v0, v0, v1, vcc_lo
; GFX11-NEXT: s_setpc_b64 s[30:31]
+;
; GFX12-LABEL: commuted_select_nan_fract_f32:
; GFX12: ; %bb.0: ; %entry
; GFX12-NEXT: s_wait_loadcnt_dscnt 0x0
@@ -1665,7 +1965,14 @@ define float @commuted_select_nan_fract_f32(float %x) {
; GFX12-NEXT: s_wait_samplecnt 0x0
; GFX12-NEXT: s_wait_bvhcnt 0x0
; GFX12-NEXT: s_wait_kmcnt 0x0
-; GFX12-NEXT: v_fract_f32_e32 v0, v0
+; GFX12-NEXT: v_floor_f32_e32 v1, v0
+; GFX12-NEXT: v_cmp_o_f32_e32 vcc_lo, v0, v0
+; GFX12-NEXT: s_delay_alu instid0(VALU_DEP_2) | instskip(NEXT) | instid1(VALU_DEP_1)
+; GFX12-NEXT: v_sub_f32_e32 v1, v0, v1
+; GFX12-NEXT: v_min_num_f32_e32 v1, 0x3f7fffff, v1
+; GFX12-NEXT: s_wait_alu depctr_va_vcc(0)
+; GFX12-NEXT: s_delay_alu instid0(VALU_DEP_1)
+; GFX12-NEXT: v_cndmask_b32_e32 v0, v0, v1, vcc_lo
; GFX12-NEXT: s_setpc_b64 s[30:31]
entry:
%floor = tail call float @llvm.floor.f32(float %x)
@@ -1751,27 +2058,13 @@ entry:
}
define half @basic_fract_f16_nonan(half nofpclass(nan) %x) {
-; GFX6-IR-LABEL: define half @basic_fract_f16_nonan(
-; GFX6-IR-SAME: half nofpclass(nan) [[X:%.*]]) {
-; GFX6-IR-NEXT: [[ENTRY:.*:]]
-; GFX6-IR-NEXT: [[FLOOR:%.*]] = tail call half @llvm.floor.f16(half [[X]])
-; GFX6-IR-NEXT: [[SUB:%.*]] = fsub half [[X]], [[FLOOR]]
-; GFX6-IR-NEXT: [[MIN:%.*]] = tail call half @llvm.minnum.f16(half [[SUB]], half 9.995110e-01)
-; GFX6-IR-NEXT: ret half [[MIN]]
-;
-; GFX7-IR-LABEL: define half @basic_fract_f16_nonan(
-; GFX7-IR-SAME: half nofpclass(nan) [[X:%.*]]) {
-; GFX7-IR-NEXT: [[ENTRY:.*:]]
-; GFX7-IR-NEXT: [[FLOOR:%.*]] = tail call half @llvm.floor.f16(half [[X]])
-; GFX7-IR-NEXT: [[SUB:%.*]] = fsub half [[X]], [[FLOOR]]
-; GFX7-IR-NEXT: [[MIN:%.*]] = tail call half @llvm.minnum.f16(half [[SUB]], half 9.995110e-01)
-; GFX7-IR-NEXT: ret half [[MIN]]
-;
-; IR-LEGALF16-LABEL: define half @basic_fract_f16_nonan(
-; IR-LEGALF16-SAME: half nofpclass(nan) [[X:%.*]]) {
-; IR-LEGALF16-NEXT: [[ENTRY:.*:]]
-; IR-LEGALF16-NEXT: [[MIN:%.*]] = call nnan half @llvm.amdgcn.fract.f16(half [[X]])
-; IR-LEGALF16-NEXT: ret half [[MIN]]
+; IR-LABEL: define half @basic_fract_f16_nonan(
+; IR-SAME: half nofpclass(nan) [[X:%.*]]) {
+; IR-NEXT: [[ENTRY:.*:]]
+; IR-NEXT: [[FLOOR:%.*]] = tail call half @llvm.floor.f16(half [[X]])
+; IR-NEXT: [[SUB:%.*]] = fsub half [[X]], [[FLOOR]]
+; IR-NEXT: [[MIN:%.*]] = tail call half @llvm.minnum.f16(half [[SUB]], half 9.995110e-01)
+; IR-NEXT: ret half [[MIN]]
;
; GFX6-LABEL: basic_fract_f16_nonan:
; GFX6: ; %bb.0: ; %entry
@@ -1786,6 +2079,7 @@ define half @basic_fract_f16_nonan(half nofpclass(nan) %x) {
; GFX6-NEXT: v_min_f32_e32 v0, 0x3f7fe000, v0
; GFX6-NEXT: v_cvt_f16_f32_e32 v0, v0
; GFX6-NEXT: s_setpc_b64 s[30:31]
+;
; GFX7-LABEL: basic_fract_f16_nonan:
; GFX7: ; %bb.0: ; %entry
; GFX7-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
@@ -1799,21 +2093,33 @@ define half @basic_fract_f16_nonan(half nofpclass(nan) %x) {
; GFX7-NEXT: v_min_f32_e32 v0, 0x3f7fe000, v0
; GFX7-NEXT: v_cvt_f16_f32_e32 v0, v0
; GFX7-NEXT: s_setpc_b64 s[30:31]
+;
; GFX8-LABEL: basic_fract_f16_nonan:
; GFX8: ; %bb.0: ; %entry
; GFX8-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX8-NEXT: v_fract_f16_e32 v0, v0
+; GFX8-NEXT: v_floor_f16_e32 v1, v0
+; GFX8-NEXT: v_sub_f16_e32 v0, v0, v1
+; GFX8-NEXT: v_min_f16_e32 v0, 0x3bff, v0
; GFX8-NEXT: s_setpc_b64 s[30:31]
+;
; GFX11-TRUE16-LABEL: basic_fract_f16_nonan:
; GFX11-TRUE16: ; %bb.0: ; %entry
; GFX11-TRUE16-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX11-TRUE16-NEXT: v_fract_f16_e32 v0.l, v0.l
+; GFX11-TRUE16-NEXT: v_floor_f16_e32 v0.h, v0.l
+; GFX11-TRUE16-NEXT: s_delay_alu instid0(VALU_DEP_1) | instskip(NEXT) | instid1(VALU_DEP_1)
+; GFX11-TRUE16-NEXT: v_sub_f16_e32 v0.l, v0.l, v0.h
+; GFX11-TRUE16-NEXT: v_min_f16_e32 v0.l, 0x3bff, v0.l
; GFX11-TRUE16-NEXT: s_setpc_b64 s[30:31]
+;
; GFX11-FAKE16-LABEL: basic_fract_f16_nonan:
; GFX11-FAKE16: ; %bb.0: ; %entry
; GFX11-FAKE16-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX11-FAKE16-NEXT: v_fract_f16_e32 v0, v0
+; GFX11-FAKE16-NEXT: v_floor_f16_e32 v1, v0
+; GFX11-FAKE16-NEXT: s_delay_alu instid0(VALU_DEP_1) | instskip(NEXT) | instid1(VALU_DEP_1)
+; GFX11-FAKE16-NEXT: v_sub_f16_e32 v0, v0, v1
+; GFX11-FAKE16-NEXT: v_min_f16_e32 v0, 0x3bff, v0
; GFX11-FAKE16-NEXT: s_setpc_b64 s[30:31]
+;
; GFX12-TRUE16-LABEL: basic_fract_f16_nonan:
; GFX12-TRUE16: ; %bb.0: ; %entry
; GFX12-TRUE16-NEXT: s_wait_loadcnt_dscnt 0x0
@@ -1821,8 +2127,12 @@ define half @basic_fract_f16_nonan(half nofpclass(nan) %x) {
; GFX12-TRUE16-NEXT: s_wait_samplecnt 0x0
; GFX12-TRUE16-NEXT: s_wait_bvhcnt 0x0
; GFX12-TRUE16-NEXT: s_wait_kmcnt 0x0
-; GFX12-TRUE16-NEXT: v_fract_f16_e32 v0.l, v0.l
+; GFX12-TRUE16-NEXT: v_floor_f16_e32 v0.h, v0.l
+; GFX12-TRUE16-NEXT: s_delay_alu instid0(VALU_DEP_1) | instskip(NEXT) | instid1(VALU_DEP_1)
+; GFX12-TRUE16-NEXT: v_sub_f16_e32 v0.l, v0.l, v0.h
+; GFX12-TRUE16-NEXT: v_min_num_f16_e32 v0.l, 0x3bff, v0.l
; GFX12-TRUE16-NEXT: s_setpc_b64 s[30:31]
+;
; GFX12-FAKE16-LABEL: basic_fract_f16_nonan:
; GFX12-FAKE16: ; %bb.0: ; %entry
; GFX12-FAKE16-NEXT: s_wait_loadcnt_dscnt 0x0
@@ -1830,7 +2140,10 @@ define half @basic_fract_f16_nonan(half nofpclass(nan) %x) {
; GFX12-FAKE16-NEXT: s_wait_samplecnt 0x0
; GFX12-FAKE16-NEXT: s_wait_bvhcnt 0x0
; GFX12-FAKE16-NEXT: s_wait_kmcnt 0x0
-; GFX12-FAKE16-NEXT: v_fract_f16_e32 v0, v0
+; GFX12-FAKE16-NEXT: v_floor_f16_e32 v1, v0
+; GFX12-FAKE16-NEXT: s_delay_alu instid0(VALU_DEP_1) | instskip(NEXT) | instid1(VALU_DEP_1)
+; GFX12-FAKE16-NEXT: v_sub_f16_e32 v0, v0, v1
+; GFX12-FAKE16-NEXT: v_min_num_f16_e32 v0, 0x3bff, v0
; GFX12-FAKE16-NEXT: s_setpc_b64 s[30:31]
entry:
%floor = tail call half @llvm.floor.f16(half %x)
@@ -1840,32 +2153,13 @@ entry:
}
define <2 x half> @basic_fract_v2f16_nonan(<2 x half> nofpclass(nan) %x) {
-; GFX6-IR-LABEL: define <2 x half> @basic_fract_v2f16_nonan(
-; GFX6-IR-SAME: <2 x half> nofpclass(nan) [[X:%.*]]) {
-; GFX6-IR-NEXT: [[ENTRY:.*:]]
-; GFX6-IR-NEXT: [[FLOOR:%.*]] = tail call <2 x half> @llvm.floor.v2f16(<2 x half> [[X]])
-; GFX6-IR-NEXT: [[SUB:%.*]] = fsub <2 x half> [[X]], [[FLOOR]]
-; GFX6-IR-NEXT: [[MIN:%.*]] = tail call <2 x half> @llvm.minnum.v2f16(<2 x half> [[SUB]], <2 x half> splat (half 9.995110e-01))
-; GFX6-IR-NEXT: ret <2 x half> [[MIN]]
-;
-; GFX7-IR-LABEL: define <2 x half> @basic_fract_v2f16_nonan(
-; GFX7-IR-SAME: <2 x half> nofpclass(nan) [[X:%.*]]) {
-; GFX7-IR-NEXT: [[ENTRY:.*:]]
-; GFX7-IR-NEXT: [[FLOOR:%.*]] = tail call <2 x half> @llvm.floor.v2f16(<2 x half> [[X]])
-; GFX7-IR-NEXT: [[SUB:%.*]] = fsub <2 x half> [[X]], [[FLOOR]]
-; GFX7-IR-NEXT: [[MIN:%.*]] = tail call <2 x half> @llvm.minnum.v2f16(<2 x half> [[SUB]], <2 x half> splat (half 9.995110e-01))
-; GFX7-IR-NEXT: ret <2 x half> [[MIN]]
-;
-; IR-LEGALF16-LABEL: define <2 x half> @basic_fract_v2f16_nonan(
-; IR-LEGALF16-SAME: <2 x half> nofpclass(nan) [[X:%.*]]) {
-; IR-LEGALF16-NEXT: [[ENTRY:.*:]]
-; IR-LEGALF16-NEXT: [[TMP0:%.*]] = extractelement <2 x half> [[X]], i64 0
-; IR-LEGALF16-NEXT: [[TMP1:%.*]] = extractelement <2 x half> [[X]], i64 1
-; IR-LEGALF16-NEXT: [[TMP2:%.*]] = call nnan half @llvm.amdgcn.fract.f16(half [[TMP0]])
-; IR-LEGALF16-NEXT: [[TMP3:%.*]] = call nnan half @llvm.amdgcn.fract.f16(half [[TMP1]])
-; IR-LEGALF16-NEXT: [[TMP4:%.*]] = insertelement <2 x half> poison, half [[TMP2]], i64 0
-; IR-LEGALF16-NEXT: [[MIN:%.*]] = insertelement <2 x half> [[TMP4]], half [[TMP3]], i64 1
-; IR-LEGALF16-NEXT: ret <2 x half> [[MIN]]
+; IR-LABEL: define <2 x half> @basic_fract_v2f16_nonan(
+; IR-SAME: <2 x half> nofpclass(nan) [[X:%.*]]) {
+; IR-NEXT: [[ENTRY:.*:]]
+; IR-NEXT: [[FLOOR:%.*]] = tail call <2 x half> @llvm.floor.v2f16(<2 x half> [[X]])
+; IR-NEXT: [[SUB:%.*]] = fsub <2 x half> [[X]], [[FLOOR]]
+; IR-NEXT: [[MIN:%.*]] = tail call <2 x half> @llvm.minnum.v2f16(<2 x half> [[SUB]], <2 x half> splat (half 9.995110e-01))
+; IR-NEXT: ret <2 x half> [[MIN]]
;
; GFX6-LABEL: basic_fract_v2f16_nonan:
; GFX6: ; %bb.0: ; %entry
@@ -1892,6 +2186,7 @@ define <2 x half> @basic_fract_v2f16_nonan(<2 x half> nofpclass(nan) %x) {
; GFX6-NEXT: v_lshlrev_b32_e32 v1, 16, v1
; GFX6-NEXT: v_or_b32_e32 v0, v0, v1
; GFX6-NEXT: s_setpc_b64 s[30:31]
+;
; GFX7-LABEL: basic_fract_v2f16_nonan:
; GFX7: ; %bb.0: ; %entry
; GFX7-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
@@ -1917,30 +2212,43 @@ define <2 x half> @basic_fract_v2f16_nonan(<2 x half> nofpclass(nan) %x) {
; GFX7-NEXT: v_lshlrev_b32_e32 v1, 16, v1
; GFX7-NEXT: v_or_b32_e32 v0, v0, v1
; GFX7-NEXT: s_setpc_b64 s[30:31]
+;
; GFX8-LABEL: basic_fract_v2f16_nonan:
; GFX8: ; %bb.0: ; %entry
; GFX8-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX8-NEXT: v_fract_f16_e32 v1, v0
-; GFX8-NEXT: v_fract_f16_sdwa v0, v0 dst_sel:DWORD dst_unused:UNUSED_PAD src0_sel:WORD_1
-; GFX8-NEXT: v_pack_b32_f16 v0, v1, v0
+; GFX8-NEXT: v_floor_f16_sdwa v1, v0 dst_sel:DWORD dst_unused:UNUSED_PAD src0_sel:WORD_1
+; GFX8-NEXT: v_floor_f16_e32 v2, v0
+; GFX8-NEXT: v_pack_b32_f16 v1, v2, v1
+; GFX8-NEXT: v_pk_add_f16 v0, v0, v1 neg_lo:[0,1] neg_hi:[0,1]
+; GFX8-NEXT: s_movk_i32 s4, 0x3bff
+; GFX8-NEXT: v_pk_min_f16 v0, v0, s4 op_sel_hi:[1,0]
; GFX8-NEXT: s_setpc_b64 s[30:31]
+;
; GFX11-TRUE16-LABEL: basic_fract_v2f16_nonan:
; GFX11-TRUE16: ; %bb.0: ; %entry
; GFX11-TRUE16-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
; GFX11-TRUE16-NEXT: v_lshrrev_b32_e32 v1, 16, v0
-; GFX11-TRUE16-NEXT: v_fract_f16_e32 v0.l, v0.l
-; GFX11-TRUE16-NEXT: s_delay_alu instid0(VALU_DEP_2)
-; GFX11-TRUE16-NEXT: v_fract_f16_e32 v0.h, v1.l
+; GFX11-TRUE16-NEXT: s_delay_alu instid0(VALU_DEP_1) | instskip(SKIP_1) | instid1(VALU_DEP_1)
+; GFX11-TRUE16-NEXT: v_floor_f16_e32 v1.h, v1.l
+; GFX11-TRUE16-NEXT: v_floor_f16_e32 v1.l, v0.l
+; GFX11-TRUE16-NEXT: v_pk_add_f16 v0, v0, v1 neg_lo:[0,1] neg_hi:[0,1]
+; GFX11-TRUE16-NEXT: s_delay_alu instid0(VALU_DEP_1)
+; GFX11-TRUE16-NEXT: v_pk_min_f16 v0, 0x3bff, v0 op_sel_hi:[0,1]
; GFX11-TRUE16-NEXT: s_setpc_b64 s[30:31]
+;
; GFX11-FAKE16-LABEL: basic_fract_v2f16_nonan:
; GFX11-FAKE16: ; %bb.0: ; %entry
; GFX11-FAKE16-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
; GFX11-FAKE16-NEXT: v_lshrrev_b32_e32 v1, 16, v0
-; GFX11-FAKE16-NEXT: v_fract_f16_e32 v0, v0
+; GFX11-FAKE16-NEXT: v_floor_f16_e32 v2, v0
; GFX11-FAKE16-NEXT: s_delay_alu instid0(VALU_DEP_2) | instskip(NEXT) | instid1(VALU_DEP_1)
-; GFX11-FAKE16-NEXT: v_fract_f16_e32 v1, v1
-; GFX11-FAKE16-NEXT: v_pack_b32_f16 v0, v0, v1
+; GFX11-FAKE16-NEXT: v_floor_f16_e32 v1, v1
+; GFX11-FAKE16-NEXT: v_pack_b32_f16 v1, v2, v1
+; GFX11-FAKE16-NEXT: s_delay_alu instid0(VALU_DEP_1) | instskip(NEXT) | instid1(VALU_DEP_1)
+; GFX11-FAKE16-NEXT: v_pk_add_f16 v0, v0, v1 neg_lo:[0,1] neg_hi:[0,1]
+; GFX11-FAKE16-NEXT: v_pk_min_f16 v0, 0x3bff, v0 op_sel_hi:[0,1]
; GFX11-FAKE16-NEXT: s_setpc_b64 s[30:31]
+;
; GFX12-TRUE16-LABEL: basic_fract_v2f16_nonan:
; GFX12-TRUE16: ; %bb.0: ; %entry
; GFX12-TRUE16-NEXT: s_wait_loadcnt_dscnt 0x0
@@ -1949,10 +2257,14 @@ define <2 x half> @basic_fract_v2f16_nonan(<2 x half> nofpclass(nan) %x) {
; GFX12-TRUE16-NEXT: s_wait_bvhcnt 0x0
; GFX12-TRUE16-NEXT: s_wait_kmcnt 0x0
; GFX12-TRUE16-NEXT: v_lshrrev_b32_e32 v1, 16, v0
-; GFX12-TRUE16-NEXT: v_fract_f16_e32 v0.l, v0.l
-; GFX12-TRUE16-NEXT: s_delay_alu instid0(VALU_DEP_2)
-; GFX12-TRUE16-NEXT: v_fract_f16_e32 v0.h, v1.l
+; GFX12-TRUE16-NEXT: s_delay_alu instid0(VALU_DEP_1) | instskip(SKIP_1) | instid1(VALU_DEP_1)
+; GFX12-TRUE16-NEXT: v_floor_f16_e32 v1.h, v1.l
+; GFX12-TRUE16-NEXT: v_floor_f16_e32 v1.l, v0.l
+; GFX12-TRUE16-NEXT: v_pk_add_f16 v0, v0, v1 neg_lo:[0,1] neg_hi:[0,1]
+; GFX12-TRUE16-NEXT: s_delay_alu instid0(VALU_DEP_1)
+; GFX12-TRUE16-NEXT: v_pk_min_num_f16 v0, 0x3bff, v0 op_sel_hi:[0,1]
; GFX12-TRUE16-NEXT: s_setpc_b64 s[30:31]
+;
; GFX12-FAKE16-LABEL: basic_fract_v2f16_nonan:
; GFX12-FAKE16: ; %bb.0: ; %entry
; GFX12-FAKE16-NEXT: s_wait_loadcnt_dscnt 0x0
@@ -1961,10 +2273,13 @@ define <2 x half> @basic_fract_v2f16_nonan(<2 x half> nofpclass(nan) %x) {
; GFX12-FAKE16-NEXT: s_wait_bvhcnt 0x0
; GFX12-FAKE16-NEXT: s_wait_kmcnt 0x0
; GFX12-FAKE16-NEXT: v_lshrrev_b32_e32 v1, 16, v0
-; GFX12-FAKE16-NEXT: v_fract_f16_e32 v0, v0
+; GFX12-FAKE16-NEXT: v_floor_f16_e32 v2, v0
; GFX12-FAKE16-NEXT: s_delay_alu instid0(VALU_DEP_2) | instskip(NEXT) | instid1(VALU_DEP_1)
-; GFX12-FAKE16-NEXT: v_fract_f16_e32 v1, v1
-; GFX12-FAKE16-NEXT: v_pack_b32_f16 v0, v0, v1
+; GFX12-FAKE16-NEXT: v_floor_f16_e32 v1, v1
+; GFX12-FAKE16-NEXT: v_pack_b32_f16 v1, v2, v1
+; GFX12-FAKE16-NEXT: s_delay_alu instid0(VALU_DEP_1) | instskip(NEXT) | instid1(VALU_DEP_1)
+; GFX12-FAKE16-NEXT: v_pk_add_f16 v0, v0, v1 neg_lo:[0,1] neg_hi:[0,1]
+; GFX12-FAKE16-NEXT: v_pk_min_num_f16 v0, 0x3bff, v0 op_sel_hi:[0,1]
; GFX12-FAKE16-NEXT: s_setpc_b64 s[30:31]
entry:
%floor = tail call <2 x half> @llvm.floor.v2f16(<2 x half> %x)
@@ -1974,19 +2289,13 @@ entry:
}
define double @basic_fract_f64_nanans(double nofpclass(nan) %x) {
-; GFX6-IR-LABEL: define double @basic_fract_f64_nanans(
-; GFX6-IR-SAME: double nofpclass(nan) [[X:%.*]]) {
-; GFX6-IR-NEXT: [[ENTRY:.*:]]
-; GFX6-IR-NEXT: [[FLOOR:%.*]] = tail call double @llvm.floor.f64(double [[X]])
-; GFX6-IR-NEXT: [[SUB:%.*]] = fsub double [[X]], [[FLOOR]]
-; GFX6-IR-NEXT: [[MIN:%.*]] = tail call double @llvm.minnum.f64(double [[SUB]], double f0x3FEFFFFFFFFFFFFF)
-; GFX6-IR-NEXT: ret double [[MIN]]
-;
-; IR-FRACT-LABEL: define double @basic_fract_f64_nanans(
-; IR-FRACT-SAME: double nofpclass(nan) [[X:%.*]]) {
-; IR-FRACT-NEXT: [[ENTRY:.*:]]
-; IR-FRACT-NEXT: [[MIN:%.*]] = call nnan double @llvm.amdgcn.fract.f64(double [[X]])
-; IR-FRACT-NEXT: ret double [[MIN]]
+; IR-LABEL: define double @basic_fract_f64_nanans(
+; IR-SAME: double nofpclass(nan) [[X:%.*]]) {
+; IR-NEXT: [[ENTRY:.*:]]
+; IR-NEXT: [[FLOOR:%.*]] = tail call double @llvm.floor.f64(double [[X]])
+; IR-NEXT: [[SUB:%.*]] = fsub double [[X]], [[FLOOR]]
+; IR-NEXT: [[MIN:%.*]] = tail call double @llvm.minnum.f64(double [[SUB]], double f0x3FEFFFFFFFFFFFFF)
+; IR-NEXT: ret double [[MIN]]
;
; GFX6-LABEL: basic_fract_f64_nanans:
; GFX6: ; %bb.0: ; %entry
@@ -2004,21 +2313,38 @@ define double @basic_fract_f64_nanans(double nofpclass(nan) %x) {
; GFX6-NEXT: v_add_f64 v[0:1], v[0:1], -v[2:3]
; GFX6-NEXT: v_min_f64 v[0:1], v[0:1], s[4:5]
; GFX6-NEXT: s_setpc_b64 s[30:31]
+;
; GFX7-LABEL: basic_fract_f64_nanans:
; GFX7: ; %bb.0: ; %entry
; GFX7-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX7-NEXT: v_fract_f64_e32 v[0:1], v[0:1]
+; GFX7-NEXT: v_floor_f64_e32 v[2:3], v[0:1]
+; GFX7-NEXT: s_mov_b32 s4, -1
+; GFX7-NEXT: s_mov_b32 s5, 0x3fefffff
+; GFX7-NEXT: v_add_f64 v[0:1], v[0:1], -v[2:3]
+; GFX7-NEXT: v_min_f64 v[0:1], v[0:1], s[4:5]
; GFX7-NEXT: s_setpc_b64 s[30:31]
+;
; GFX8-LABEL: basic_fract_f64_nanans:
; GFX8: ; %bb.0: ; %entry
; GFX8-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX8-NEXT: v_fract_f64_e32 v[0:1], v[0:1]
+; GFX8-NEXT: v_floor_f64_e32 v[2:3], v[0:1]
+; GFX8-NEXT: s_mov_b32 s4, -1
+; GFX8-NEXT: s_mov_b32 s5, 0x3fefffff
+; GFX8-NEXT: v_add_f64 v[0:1], v[0:1], -v[2:3]
+; GFX8-NEXT: v_min_f64 v[0:1], v[0:1], s[4:5]
; GFX8-NEXT: s_setpc_b64 s[30:31]
+;
; GFX11-LABEL: basic_fract_f64_nanans:
; GFX11: ; %bb.0: ; %entry
; GFX11-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX11-NEXT: v_fract_f64_e32 v[0:1], v[0:1]
+; GFX11-NEXT: v_floor_f64_e32 v[2:3], v[0:1]
+; GFX11-NEXT: s_mov_b32 s0, -1
+; GFX11-NEXT: s_mov_b32 s1, 0x3fefffff
+; GFX11-NEXT: s_delay_alu instid0(VALU_DEP_1) | instskip(NEXT) | instid1(VALU_DEP_1)
+; GFX11-NEXT: v_add_f64 v[0:1], v[0:1], -v[2:3]
+; GFX11-NEXT: v_min_f64 v[0:1], v[0:1], s[0:1]
; GFX11-NEXT: s_setpc_b64 s[30:31]
+;
; GFX12-LABEL: basic_fract_f64_nanans:
; GFX12: ; %bb.0: ; %entry
; GFX12-NEXT: s_wait_loadcnt_dscnt 0x0
@@ -2026,7 +2352,13 @@ define double @basic_fract_f64_nanans(double nofpclass(nan) %x) {
; GFX12-NEXT: s_wait_samplecnt 0x0
; GFX12-NEXT: s_wait_bvhcnt 0x0
; GFX12-NEXT: s_wait_kmcnt 0x0
-; GFX12-NEXT: v_fract_f64_e32 v[0:1], v[0:1]
+; GFX12-NEXT: v_floor_f64_e32 v[2:3], v[0:1]
+; GFX12-NEXT: s_mov_b32 s0, -1
+; GFX12-NEXT: s_mov_b32 s1, 0x3fefffff
+; GFX12-NEXT: s_delay_alu instid0(VALU_DEP_1) | instskip(SKIP_1) | instid1(VALU_DEP_1)
+; GFX12-NEXT: v_add_f64_e64 v[0:1], v[0:1], -v[2:3]
+; GFX12-NEXT: s_wait_alu depctr_sa_sdst(0)
+; GFX12-NEXT: v_min_num_f64_e32 v[0:1], s[0:1], v[0:1]
; GFX12-NEXT: s_setpc_b64 s[30:31]
entry:
%floor = tail call double @llvm.floor.f64(double %x)
@@ -2036,35 +2368,16 @@ entry:
}
define half @safe_math_fract_f16_noinf_check(half %x, ptr addrspace(1) writeonly captures(none) %ip) {
-; GFX6-IR-LABEL: define half @safe_math_fract_f16_noinf_check(
-; GFX6-IR-SAME: half [[X:%.*]], ptr addrspace(1) writeonly captures(none) [[IP:%.*]]) {
-; GFX6-IR-NEXT: [[ENTRY:.*:]]
-; GFX6-IR-NEXT: [[FLOOR:%.*]] = tail call half @llvm.floor.f16(half [[X]])
-; GFX6-IR-NEXT: [[SUB:%.*]] = fsub half [[X]], [[FLOOR]]
-; GFX6-IR-NEXT: [[MIN:%.*]] = tail call half @llvm.minnum.f16(half [[SUB]], half 9.995110e-01)
-; GFX6-IR-NEXT: [[UNO:%.*]] = fcmp uno half [[X]], 0.000000e+00
-; GFX6-IR-NEXT: [[COND:%.*]] = select i1 [[UNO]], half [[X]], half [[MIN]]
-; GFX6-IR-NEXT: store half [[FLOOR]], ptr addrspace(1) [[IP]], align 4
-; GFX6-IR-NEXT: ret half [[COND]]
-;
-; GFX7-IR-LABEL: define half @safe_math_fract_f16_noinf_check(
-; GFX7-IR-SAME: half [[X:%.*]], ptr addrspace(1) writeonly captures(none) [[IP:%.*]]) {
-; GFX7-IR-NEXT: [[ENTRY:.*:]]
-; GFX7-IR-NEXT: [[FLOOR:%.*]] = tail call half @llvm.floor.f16(half [[X]])
-; GFX7-IR-NEXT: [[SUB:%.*]] = fsub half [[X]], [[FLOOR]]
-; GFX7-IR-NEXT: [[MIN:%.*]] = tail call half @llvm.minnum.f16(half [[SUB]], half 9.995110e-01)
-; GFX7-IR-NEXT: [[UNO:%.*]] = fcmp uno half [[X]], 0.000000e+00
-; GFX7-IR-NEXT: [[COND:%.*]] = select i1 [[UNO]], half [[X]], half [[MIN]]
-; GFX7-IR-NEXT: store half [[FLOOR]], ptr addrspace(1) [[IP]], align 4
-; GFX7-IR-NEXT: ret half [[COND]]
-;
-; IR-LEGALF16-LABEL: define half @safe_math_fract_f16_noinf_check(
-; IR-LEGALF16-SAME: half [[X:%.*]], ptr addrspace(1) writeonly captures(none) [[IP:%.*]]) {
-; IR-LEGALF16-NEXT: [[ENTRY:.*:]]
-; IR-LEGALF16-NEXT: [[FLOOR:%.*]] = tail call half @llvm.floor.f16(half [[X]])
-; IR-LEGALF16-NEXT: [[COND:%.*]] = call half @llvm.amdgcn.fract.f16(half [[X]])
-; IR-LEGALF16-NEXT: store half [[FLOOR]], ptr addrspace(1) [[IP]], align 4
-; IR-LEGALF16-NEXT: ret half [[COND]]
+; IR-LABEL: define half @safe_math_fract_f16_noinf_check(
+; IR-SAME: half [[X:%.*]], ptr addrspace(1) writeonly captures(none) [[IP:%.*]]) {
+; IR-NEXT: [[ENTRY:.*:]]
+; IR-NEXT: [[FLOOR:%.*]] = tail call half @llvm.floor.f16(half [[X]])
+; IR-NEXT: [[SUB:%.*]] = fsub half [[X]], [[FLOOR]]
+; IR-NEXT: [[MIN:%.*]] = tail call half @llvm.minnum.f16(half [[SUB]], half 9.995110e-01)
+; IR-NEXT: [[UNO:%.*]] = fcmp uno half [[X]], 0.000000e+00
+; IR-NEXT: [[COND:%.*]] = select i1 [[UNO]], half [[X]], half [[MIN]]
+; IR-NEXT: store half [[FLOOR]], ptr addrspace(1) [[IP]], align 4
+; IR-NEXT: ret half [[COND]]
;
; GFX6-LABEL: safe_math_fract_f16_noinf_check:
; GFX6: ; %bb.0: ; %entry
@@ -2087,6 +2400,7 @@ define half @safe_math_fract_f16_noinf_check(half %x, ptr addrspace(1) writeonly
; GFX6-NEXT: v_cndmask_b32_e32 v0, v5, v0, vcc
; GFX6-NEXT: s_waitcnt vmcnt(0) expcnt(0)
; GFX6-NEXT: s_setpc_b64 s[30:31]
+;
; GFX7-LABEL: safe_math_fract_f16_noinf_check:
; GFX7: ; %bb.0: ; %entry
; GFX7-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
@@ -2108,28 +2422,43 @@ define half @safe_math_fract_f16_noinf_check(half %x, ptr addrspace(1) writeonly
; GFX7-NEXT: v_cndmask_b32_e32 v0, v5, v0, vcc
; GFX7-NEXT: s_waitcnt vmcnt(0)
; GFX7-NEXT: s_setpc_b64 s[30:31]
+;
; GFX8-LABEL: safe_math_fract_f16_noinf_check:
; GFX8: ; %bb.0: ; %entry
; GFX8-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
; GFX8-NEXT: v_floor_f16_e32 v3, v0
-; GFX8-NEXT: v_fract_f16_e32 v0, v0
+; GFX8-NEXT: v_sub_f16_e32 v4, v0, v3
+; GFX8-NEXT: v_min_f16_e32 v4, 0x3bff, v4
+; GFX8-NEXT: v_cmp_u_f16_e32 vcc, v0, v0
+; GFX8-NEXT: v_cndmask_b32_e32 v0, v4, v0, vcc
; GFX8-NEXT: global_store_short v[1:2], v3, off
; GFX8-NEXT: s_waitcnt vmcnt(0)
; GFX8-NEXT: s_setpc_b64 s[30:31]
+;
; GFX11-TRUE16-LABEL: safe_math_fract_f16_noinf_check:
; GFX11-TRUE16: ; %bb.0: ; %entry
; GFX11-TRUE16-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
; GFX11-TRUE16-NEXT: v_floor_f16_e32 v0.h, v0.l
-; GFX11-TRUE16-NEXT: v_fract_f16_e32 v0.l, v0.l
+; GFX11-TRUE16-NEXT: v_cmp_u_f16_e32 vcc_lo, v0.l, v0.l
+; GFX11-TRUE16-NEXT: s_delay_alu instid0(VALU_DEP_2) | instskip(SKIP_2) | instid1(VALU_DEP_1)
+; GFX11-TRUE16-NEXT: v_sub_f16_e32 v3.l, v0.l, v0.h
; GFX11-TRUE16-NEXT: global_store_d16_hi_b16 v[1:2], v0, off
+; GFX11-TRUE16-NEXT: v_min_f16_e32 v3.l, 0x3bff, v3.l
+; GFX11-TRUE16-NEXT: v_cndmask_b16 v0.l, v3.l, v0.l, vcc_lo
; GFX11-TRUE16-NEXT: s_setpc_b64 s[30:31]
+;
; GFX11-FAKE16-LABEL: safe_math_fract_f16_noinf_check:
; GFX11-FAKE16: ; %bb.0: ; %entry
; GFX11-FAKE16-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
; GFX11-FAKE16-NEXT: v_floor_f16_e32 v3, v0
-; GFX11-FAKE16-NEXT: v_fract_f16_e32 v0, v0
+; GFX11-FAKE16-NEXT: v_cmp_u_f16_e32 vcc_lo, v0, v0
+; GFX11-FAKE16-NEXT: s_delay_alu instid0(VALU_DEP_2) | instskip(SKIP_2) | instid1(VALU_DEP_1)
+; GFX11-FAKE16-NEXT: v_sub_f16_e32 v4, v0, v3
; GFX11-FAKE16-NEXT: global_store_b16 v[1:2], v3, off
+; GFX11-FAKE16-NEXT: v_min_f16_e32 v4, 0x3bff, v4
+; GFX11-FAKE16-NEXT: v_cndmask_b32_e32 v0, v4, v0, vcc_lo
; GFX11-FAKE16-NEXT: s_setpc_b64 s[30:31]
+;
; GFX12-TRUE16-LABEL: safe_math_fract_f16_noinf_check:
; GFX12-TRUE16: ; %bb.0: ; %entry
; GFX12-TRUE16-NEXT: s_wait_loadcnt_dscnt 0x0
@@ -2138,9 +2467,15 @@ define half @safe_math_fract_f16_noinf_check(half %x, ptr addrspace(1) writeonly
; GFX12-TRUE16-NEXT: s_wait_bvhcnt 0x0
; GFX12-TRUE16-NEXT: s_wait_kmcnt 0x0
; GFX12-TRUE16-NEXT: v_floor_f16_e32 v0.h, v0.l
-; GFX12-TRUE16-NEXT: v_fract_f16_e32 v0.l, v0.l
+; GFX12-TRUE16-NEXT: v_cmp_u_f16_e32 vcc_lo, v0.l, v0.l
+; GFX12-TRUE16-NEXT: s_delay_alu instid0(VALU_DEP_2) | instskip(SKIP_3) | instid1(VALU_DEP_1)
+; GFX12-TRUE16-NEXT: v_sub_f16_e32 v3.l, v0.l, v0.h
; GFX12-TRUE16-NEXT: global_store_d16_hi_b16 v[1:2], v0, off
+; GFX12-TRUE16-NEXT: v_min_num_f16_e32 v3.l, 0x3bff, v3.l
+; GFX12-TRUE16-NEXT: s_wait_alu depctr_va_vcc(0)
+; GFX12-TRUE16-NEXT: v_cndmask_b16 v0.l, v3.l, v0.l, vcc_lo
; GFX12-TRUE16-NEXT: s_setpc_b64 s[30:31]
+;
; GFX12-FAKE16-LABEL: safe_math_fract_f16_noinf_check:
; GFX12-FAKE16: ; %bb.0: ; %entry
; GFX12-FAKE16-NEXT: s_wait_loadcnt_dscnt 0x0
@@ -2149,8 +2484,13 @@ define half @safe_math_fract_f16_noinf_check(half %x, ptr addrspace(1) writeonly
; GFX12-FAKE16-NEXT: s_wait_bvhcnt 0x0
; GFX12-FAKE16-NEXT: s_wait_kmcnt 0x0
; GFX12-FAKE16-NEXT: v_floor_f16_e32 v3, v0
-; GFX12-FAKE16-NEXT: v_fract_f16_e32 v0, v0
+; GFX12-FAKE16-NEXT: v_cmp_u_f16_e32 vcc_lo, v0, v0
+; GFX12-FAKE16-NEXT: s_delay_alu instid0(VALU_DEP_2) | instskip(SKIP_3) | instid1(VALU_DEP_1)
+; GFX12-FAKE16-NEXT: v_sub_f16_e32 v4, v0, v3
; GFX12-FAKE16-NEXT: global_store_b16 v[1:2], v3, off
+; GFX12-FAKE16-NEXT: v_min_num_f16_e32 v4, 0x3bff, v4
+; GFX12-FAKE16-NEXT: s_wait_alu depctr_va_vcc(0)
+; GFX12-FAKE16-NEXT: v_cndmask_b32_e32 v0, v4, v0, vcc_lo
; GFX12-FAKE16-NEXT: s_setpc_b64 s[30:31]
entry:
%floor = tail call half @llvm.floor.f16(half %x)
@@ -2163,24 +2503,16 @@ entry:
}
define double @safe_math_fract_f64_noinf_check(double %x, ptr addrspace(1) writeonly captures(none) %ip) {
-; GFX6-IR-LABEL: define double @safe_math_fract_f64_noinf_check(
-; GFX6-IR-SAME: double [[X:%.*]], ptr addrspace(1) writeonly captures(none) [[IP:%.*]]) {
-; GFX6-IR-NEXT: [[ENTRY:.*:]]
-; GFX6-IR-NEXT: [[FLOOR:%.*]] = tail call double @llvm.floor.f64(double [[X]])
-; GFX6-IR-NEXT: [[SUB:%.*]] = fsub double [[X]], [[FLOOR]]
-; GFX6-IR-NEXT: [[MIN:%.*]] = tail call double @llvm.minnum.f64(double [[SUB]], double f0x3FEFFFFFFFFFFFFF)
-; GFX6-IR-NEXT: [[UNO:%.*]] = fcmp uno double [[X]], 0.000000e+00
-; GFX6-IR-NEXT: [[COND:%.*]] = select i1 [[UNO]], double [[X]], double [[MIN]]
-; GFX6-IR-NEXT: store double [[FLOOR]], ptr addrspace(1) [[IP]], align 4
-; GFX6-IR-NEXT: ret double [[COND]]
-;
-; IR-FRACT-LABEL: define double @safe_math_fract_f64_noinf_check(
-; IR-FRACT-SAME: double [[X:%.*]], ptr addrspace(1) writeonly captures(none) [[IP:%.*]]) {
-; IR-FRACT-NEXT: [[ENTRY:.*:]]
-; IR-FRACT-NEXT: [[FLOOR:%.*]] = tail call double @llvm.floor.f64(double [[X]])
-; IR-FRACT-NEXT: [[COND:%.*]] = call double @llvm.amdgcn.fract.f64(double [[X]])
-; IR-FRACT-NEXT: store double [[FLOOR]], ptr addrspace(1) [[IP]], align 4
-; IR-FRACT-NEXT: ret double [[COND]]
+; IR-LABEL: define double @safe_math_fract_f64_noinf_check(
+; IR-SAME: double [[X:%.*]], ptr addrspace(1) writeonly captures(none) [[IP:%.*]]) {
+; IR-NEXT: [[ENTRY:.*:]]
+; IR-NEXT: [[FLOOR:%.*]] = tail call double @llvm.floor.f64(double [[X]])
+; IR-NEXT: [[SUB:%.*]] = fsub double [[X]], [[FLOOR]]
+; IR-NEXT: [[MIN:%.*]] = tail call double @llvm.minnum.f64(double [[SUB]], double f0x3FEFFFFFFFFFFFFF)
+; IR-NEXT: [[UNO:%.*]] = fcmp uno double [[X]], 0.000000e+00
+; IR-NEXT: [[COND:%.*]] = select i1 [[UNO]], double [[X]], double [[MIN]]
+; IR-NEXT: store double [[FLOOR]], ptr addrspace(1) [[IP]], align 4
+; IR-NEXT: ret double [[COND]]
;
; GFX6-LABEL: safe_math_fract_f64_noinf_check:
; GFX6: ; %bb.0: ; %entry
@@ -2207,72 +2539,336 @@ define double @safe_math_fract_f64_noinf_check(double %x, ptr addrspace(1) write
; GFX6-NEXT: buffer_store_dwordx2 v[4:5], v[2:3], s[4:7], 0 addr64
; GFX6-NEXT: s_waitcnt vmcnt(0) expcnt(0)
; GFX6-NEXT: s_setpc_b64 s[30:31]
-; GFX7-LABEL: safe_math_fract_f64_noinf_check:
+;
+; GFX7-LABEL: safe_math_fract_f64_noinf_check:
+; GFX7: ; %bb.0: ; %entry
+; GFX7-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX7-NEXT: v_floor_f64_e32 v[4:5], v[0:1]
+; GFX7-NEXT: s_mov_b32 s4, -1
+; GFX7-NEXT: s_mov_b32 s5, 0x3fefffff
+; GFX7-NEXT: v_cmp_u_f64_e32 vcc, v[0:1], v[0:1]
+; GFX7-NEXT: s_mov_b32 s6, 0
+; GFX7-NEXT: s_mov_b32 s7, 0xf000
+; GFX7-NEXT: v_add_f64 v[6:7], v[0:1], -v[4:5]
+; GFX7-NEXT: v_min_f64 v[6:7], v[6:7], s[4:5]
+; GFX7-NEXT: s_mov_b32 s4, s6
+; GFX7-NEXT: s_mov_b32 s5, s6
+; GFX7-NEXT: buffer_store_dwordx2 v[4:5], v[2:3], s[4:7], 0 addr64
+; GFX7-NEXT: v_cndmask_b32_e32 v0, v6, v0, vcc
+; GFX7-NEXT: v_cndmask_b32_e32 v1, v7, v1, vcc
+; GFX7-NEXT: s_waitcnt vmcnt(0)
+; GFX7-NEXT: s_setpc_b64 s[30:31]
+;
+; GFX8-LABEL: safe_math_fract_f64_noinf_check:
+; GFX8: ; %bb.0: ; %entry
+; GFX8-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX8-NEXT: v_floor_f64_e32 v[4:5], v[0:1]
+; GFX8-NEXT: s_mov_b32 s4, -1
+; GFX8-NEXT: s_mov_b32 s5, 0x3fefffff
+; GFX8-NEXT: v_cmp_u_f64_e32 vcc, v[0:1], v[0:1]
+; GFX8-NEXT: v_add_f64 v[6:7], v[0:1], -v[4:5]
+; GFX8-NEXT: global_store_dwordx2 v[2:3], v[4:5], off
+; GFX8-NEXT: v_min_f64 v[6:7], v[6:7], s[4:5]
+; GFX8-NEXT: v_cndmask_b32_e32 v0, v6, v0, vcc
+; GFX8-NEXT: v_cndmask_b32_e32 v1, v7, v1, vcc
+; GFX8-NEXT: s_waitcnt vmcnt(0)
+; GFX8-NEXT: s_setpc_b64 s[30:31]
+;
+; GFX11-LABEL: safe_math_fract_f64_noinf_check:
+; GFX11: ; %bb.0: ; %entry
+; GFX11-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-NEXT: v_floor_f64_e32 v[4:5], v[0:1]
+; GFX11-NEXT: s_mov_b32 s0, -1
+; GFX11-NEXT: s_mov_b32 s1, 0x3fefffff
+; GFX11-NEXT: v_cmp_u_f64_e32 vcc_lo, v[0:1], v[0:1]
+; GFX11-NEXT: s_delay_alu instid0(VALU_DEP_2) | instskip(SKIP_2) | instid1(VALU_DEP_1)
+; GFX11-NEXT: v_add_f64 v[6:7], v[0:1], -v[4:5]
+; GFX11-NEXT: global_store_b64 v[2:3], v[4:5], off
+; GFX11-NEXT: v_min_f64 v[6:7], v[6:7], s[0:1]
+; GFX11-NEXT: v_dual_cndmask_b32 v0, v6, v0 :: v_dual_cndmask_b32 v1, v7, v1
+; GFX11-NEXT: s_setpc_b64 s[30:31]
+;
+; GFX12-LABEL: safe_math_fract_f64_noinf_check:
+; GFX12: ; %bb.0: ; %entry
+; GFX12-NEXT: s_wait_loadcnt_dscnt 0x0
+; GFX12-NEXT: s_wait_expcnt 0x0
+; GFX12-NEXT: s_wait_samplecnt 0x0
+; GFX12-NEXT: s_wait_bvhcnt 0x0
+; GFX12-NEXT: s_wait_kmcnt 0x0
+; GFX12-NEXT: v_floor_f64_e32 v[4:5], v[0:1]
+; GFX12-NEXT: s_mov_b32 s0, -1
+; GFX12-NEXT: s_mov_b32 s1, 0x3fefffff
+; GFX12-NEXT: v_cmp_u_f64_e32 vcc_lo, v[0:1], v[0:1]
+; GFX12-NEXT: s_delay_alu instid0(VALU_DEP_2) | instskip(SKIP_4) | instid1(VALU_DEP_1)
+; GFX12-NEXT: v_add_f64_e64 v[6:7], v[0:1], -v[4:5]
+; GFX12-NEXT: global_store_b64 v[2:3], v[4:5], off
+; GFX12-NEXT: s_wait_alu depctr_sa_sdst(0)
+; GFX12-NEXT: v_min_num_f64_e32 v[6:7], s[0:1], v[6:7]
+; GFX12-NEXT: s_wait_alu depctr_va_vcc(0)
+; GFX12-NEXT: v_dual_cndmask_b32 v0, v6, v0 :: v_dual_cndmask_b32 v1, v7, v1
+; GFX12-NEXT: s_setpc_b64 s[30:31]
+entry:
+ %floor = tail call double @llvm.floor.f64(double %x)
+ %sub = fsub double %x, %floor
+ %min = tail call double @llvm.minnum.f64(double %sub, double 0x3FEFFFFFFFFFFFFF)
+ %uno = fcmp uno double %x, 0.000000e+00
+ %cond = select i1 %uno, double %x, double %min
+ store double %floor, ptr addrspace(1) %ip, align 4
+ ret double %cond
+}
+
+define float @select_nan_fract_f32_flags_select(float %x) {
+; IR-LABEL: define float @select_nan_fract_f32_flags_select(
+; IR-SAME: float [[X:%.*]]) {
+; IR-NEXT: [[ENTRY:.*:]]
+; IR-NEXT: [[FLOOR:%.*]] = tail call float @llvm.floor.f32(float [[X]])
+; IR-NEXT: [[SUB:%.*]] = fsub float [[X]], [[FLOOR]]
+; IR-NEXT: [[MIN:%.*]] = tail call float @llvm.minnum.f32(float [[SUB]], float f0x3F7FFFFF)
+; IR-NEXT: [[UNO:%.*]] = fcmp uno float [[X]], 0.000000e+00
+; IR-NEXT: [[COND:%.*]] = select nsz i1 [[UNO]], float [[X]], float [[MIN]]
+; IR-NEXT: ret float [[COND]]
+;
+; GFX6-LABEL: select_nan_fract_f32_flags_select:
+; GFX6: ; %bb.0: ; %entry
+; GFX6-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX6-NEXT: v_floor_f32_e32 v1, v0
+; GFX6-NEXT: v_sub_f32_e32 v1, v0, v1
+; GFX6-NEXT: v_min_f32_e32 v1, 0x3f7fffff, v1
+; GFX6-NEXT: v_cmp_u_f32_e32 vcc, v0, v0
+; GFX6-NEXT: v_cndmask_b32_e32 v0, v1, v0, vcc
+; GFX6-NEXT: s_setpc_b64 s[30:31]
+;
+; GFX7-LABEL: select_nan_fract_f32_flags_select:
+; GFX7: ; %bb.0: ; %entry
+; GFX7-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX7-NEXT: v_floor_f32_e32 v1, v0
+; GFX7-NEXT: v_sub_f32_e32 v1, v0, v1
+; GFX7-NEXT: v_min_f32_e32 v1, 0x3f7fffff, v1
+; GFX7-NEXT: v_cmp_u_f32_e32 vcc, v0, v0
+; GFX7-NEXT: v_cndmask_b32_e32 v0, v1, v0, vcc
+; GFX7-NEXT: s_setpc_b64 s[30:31]
+;
+; GFX8-LABEL: select_nan_fract_f32_flags_select:
+; GFX8: ; %bb.0: ; %entry
+; GFX8-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX8-NEXT: v_floor_f32_e32 v1, v0
+; GFX8-NEXT: v_sub_f32_e32 v1, v0, v1
+; GFX8-NEXT: v_min_f32_e32 v1, 0x3f7fffff, v1
+; GFX8-NEXT: v_cmp_u_f32_e32 vcc, v0, v0
+; GFX8-NEXT: v_cndmask_b32_e32 v0, v1, v0, vcc
+; GFX8-NEXT: s_setpc_b64 s[30:31]
+;
+; GFX11-LABEL: select_nan_fract_f32_flags_select:
+; GFX11: ; %bb.0: ; %entry
+; GFX11-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-NEXT: v_floor_f32_e32 v1, v0
+; GFX11-NEXT: v_cmp_u_f32_e32 vcc_lo, v0, v0
+; GFX11-NEXT: s_delay_alu instid0(VALU_DEP_2) | instskip(NEXT) | instid1(VALU_DEP_1)
+; GFX11-NEXT: v_sub_f32_e32 v1, v0, v1
+; GFX11-NEXT: v_min_f32_e32 v1, 0x3f7fffff, v1
+; GFX11-NEXT: s_delay_alu instid0(VALU_DEP_1)
+; GFX11-NEXT: v_cndmask_b32_e32 v0, v1, v0, vcc_lo
+; GFX11-NEXT: s_setpc_b64 s[30:31]
+;
+; GFX12-LABEL: select_nan_fract_f32_flags_select:
+; GFX12: ; %bb.0: ; %entry
+; GFX12-NEXT: s_wait_loadcnt_dscnt 0x0
+; GFX12-NEXT: s_wait_expcnt 0x0
+; GFX12-NEXT: s_wait_samplecnt 0x0
+; GFX12-NEXT: s_wait_bvhcnt 0x0
+; GFX12-NEXT: s_wait_kmcnt 0x0
+; GFX12-NEXT: v_floor_f32_e32 v1, v0
+; GFX12-NEXT: v_cmp_u_f32_e32 vcc_lo, v0, v0
+; GFX12-NEXT: s_delay_alu instid0(VALU_DEP_2) | instskip(NEXT) | instid1(VALU_DEP_1)
+; GFX12-NEXT: v_sub_f32_e32 v1, v0, v1
+; GFX12-NEXT: v_min_num_f32_e32 v1, 0x3f7fffff, v1
+; GFX12-NEXT: s_wait_alu depctr_va_vcc(0)
+; GFX12-NEXT: s_delay_alu instid0(VALU_DEP_1)
+; GFX12-NEXT: v_cndmask_b32_e32 v0, v1, v0, vcc_lo
+; GFX12-NEXT: s_setpc_b64 s[30:31]
+entry:
+ %floor = tail call float @llvm.floor.f32(float %x)
+ %sub = fsub float %x, %floor
+ %min = tail call float @llvm.minnum.f32(float %sub, float 0x3FEFFFFFE0000000)
+ %uno = fcmp uno float %x, 0.000000e+00
+ %cond = select nsz i1 %uno, float %x, float %min
+ ret float %cond
+}
+
+define float @select_nan_fract_f32_flags_minnum(float %x) {
+; IR-LABEL: define float @select_nan_fract_f32_flags_minnum(
+; IR-SAME: float [[X:%.*]]) {
+; IR-NEXT: [[ENTRY:.*:]]
+; IR-NEXT: [[FLOOR:%.*]] = tail call float @llvm.floor.f32(float [[X]])
+; IR-NEXT: [[SUB:%.*]] = fsub float [[X]], [[FLOOR]]
+; IR-NEXT: [[MIN:%.*]] = tail call nsz float @llvm.minnum.f32(float [[SUB]], float f0x3F7FFFFF)
+; IR-NEXT: [[UNO:%.*]] = fcmp uno float [[X]], 0.000000e+00
+; IR-NEXT: [[COND:%.*]] = select i1 [[UNO]], float [[X]], float [[MIN]]
+; IR-NEXT: ret float [[COND]]
+;
+; GFX6-LABEL: select_nan_fract_f32_flags_minnum:
+; GFX6: ; %bb.0: ; %entry
+; GFX6-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX6-NEXT: v_floor_f32_e32 v1, v0
+; GFX6-NEXT: v_sub_f32_e32 v1, v0, v1
+; GFX6-NEXT: v_min_f32_e32 v1, 0x3f7fffff, v1
+; GFX6-NEXT: v_cmp_u_f32_e32 vcc, v0, v0
+; GFX6-NEXT: v_cndmask_b32_e32 v0, v1, v0, vcc
+; GFX6-NEXT: s_setpc_b64 s[30:31]
+;
+; GFX7-LABEL: select_nan_fract_f32_flags_minnum:
+; GFX7: ; %bb.0: ; %entry
+; GFX7-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX7-NEXT: v_floor_f32_e32 v1, v0
+; GFX7-NEXT: v_sub_f32_e32 v1, v0, v1
+; GFX7-NEXT: v_min_f32_e32 v1, 0x3f7fffff, v1
+; GFX7-NEXT: v_cmp_u_f32_e32 vcc, v0, v0
+; GFX7-NEXT: v_cndmask_b32_e32 v0, v1, v0, vcc
+; GFX7-NEXT: s_setpc_b64 s[30:31]
+;
+; GFX8-LABEL: select_nan_fract_f32_flags_minnum:
+; GFX8: ; %bb.0: ; %entry
+; GFX8-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX8-NEXT: v_floor_f32_e32 v1, v0
+; GFX8-NEXT: v_sub_f32_e32 v1, v0, v1
+; GFX8-NEXT: v_min_f32_e32 v1, 0x3f7fffff, v1
+; GFX8-NEXT: v_cmp_u_f32_e32 vcc, v0, v0
+; GFX8-NEXT: v_cndmask_b32_e32 v0, v1, v0, vcc
+; GFX8-NEXT: s_setpc_b64 s[30:31]
+;
+; GFX11-LABEL: select_nan_fract_f32_flags_minnum:
+; GFX11: ; %bb.0: ; %entry
+; GFX11-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-NEXT: v_floor_f32_e32 v1, v0
+; GFX11-NEXT: v_cmp_u_f32_e32 vcc_lo, v0, v0
+; GFX11-NEXT: s_delay_alu instid0(VALU_DEP_2) | instskip(NEXT) | instid1(VALU_DEP_1)
+; GFX11-NEXT: v_sub_f32_e32 v1, v0, v1
+; GFX11-NEXT: v_min_f32_e32 v1, 0x3f7fffff, v1
+; GFX11-NEXT: s_delay_alu instid0(VALU_DEP_1)
+; GFX11-NEXT: v_cndmask_b32_e32 v0, v1, v0, vcc_lo
+; GFX11-NEXT: s_setpc_b64 s[30:31]
+;
+; GFX12-LABEL: select_nan_fract_f32_flags_minnum:
+; GFX12: ; %bb.0: ; %entry
+; GFX12-NEXT: s_wait_loadcnt_dscnt 0x0
+; GFX12-NEXT: s_wait_expcnt 0x0
+; GFX12-NEXT: s_wait_samplecnt 0x0
+; GFX12-NEXT: s_wait_bvhcnt 0x0
+; GFX12-NEXT: s_wait_kmcnt 0x0
+; GFX12-NEXT: v_floor_f32_e32 v1, v0
+; GFX12-NEXT: v_cmp_u_f32_e32 vcc_lo, v0, v0
+; GFX12-NEXT: s_delay_alu instid0(VALU_DEP_2) | instskip(NEXT) | instid1(VALU_DEP_1)
+; GFX12-NEXT: v_sub_f32_e32 v1, v0, v1
+; GFX12-NEXT: v_min_num_f32_e32 v1, 0x3f7fffff, v1
+; GFX12-NEXT: s_wait_alu depctr_va_vcc(0)
+; GFX12-NEXT: s_delay_alu instid0(VALU_DEP_1)
+; GFX12-NEXT: v_cndmask_b32_e32 v0, v1, v0, vcc_lo
+; GFX12-NEXT: s_setpc_b64 s[30:31]
+entry:
+ %floor = tail call float @llvm.floor.f32(float %x)
+ %sub = fsub float %x, %floor
+ %min = tail call nsz float @llvm.minnum.f32(float %sub, float 0x3FEFFFFFE0000000)
+ %uno = fcmp uno float %x, 0.000000e+00
+ %cond = select i1 %uno, float %x, float %min
+ ret float %cond
+}
+
+define float @select_nan_fract_f32_ninf_minnum(float %x) {
+; IR-LABEL: define float @select_nan_fract_f32_ninf_minnum(
+; IR-SAME: float [[X:%.*]]) {
+; IR-NEXT: [[ENTRY:.*:]]
+; IR-NEXT: [[FLOOR:%.*]] = tail call float @llvm.floor.f32(float [[X]])
+; IR-NEXT: [[SUB:%.*]] = fsub float [[X]], [[FLOOR]]
+; IR-NEXT: [[MIN:%.*]] = tail call ninf float @llvm.minnum.f32(float [[SUB]], float f0x3F7FFFFF)
+; IR-NEXT: [[UNO:%.*]] = fcmp uno float [[X]], 0.000000e+00
+; IR-NEXT: [[COND:%.*]] = select i1 [[UNO]], float [[X]], float [[MIN]]
+; IR-NEXT: ret float [[COND]]
+;
+; GFX6-LABEL: select_nan_fract_f32_ninf_minnum:
+; GFX6: ; %bb.0: ; %entry
+; GFX6-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX6-NEXT: v_floor_f32_e32 v1, v0
+; GFX6-NEXT: v_sub_f32_e32 v1, v0, v1
+; GFX6-NEXT: v_min_f32_e32 v1, 0x3f7fffff, v1
+; GFX6-NEXT: v_cmp_u_f32_e32 vcc, v0, v0
+; GFX6-NEXT: v_cndmask_b32_e32 v0, v1, v0, vcc
+; GFX6-NEXT: s_setpc_b64 s[30:31]
+;
+; GFX7-LABEL: select_nan_fract_f32_ninf_minnum:
; GFX7: ; %bb.0: ; %entry
; GFX7-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX7-NEXT: v_floor_f64_e32 v[4:5], v[0:1]
-; GFX7-NEXT: v_fract_f64_e32 v[0:1], v[0:1]
-; GFX7-NEXT: s_mov_b32 s6, 0
-; GFX7-NEXT: s_mov_b32 s7, 0xf000
-; GFX7-NEXT: s_mov_b32 s4, s6
-; GFX7-NEXT: s_mov_b32 s5, s6
-; GFX7-NEXT: buffer_store_dwordx2 v[4:5], v[2:3], s[4:7], 0 addr64
-; GFX7-NEXT: s_waitcnt vmcnt(0)
+; GFX7-NEXT: v_floor_f32_e32 v1, v0
+; GFX7-NEXT: v_sub_f32_e32 v1, v0, v1
+; GFX7-NEXT: v_min_f32_e32 v1, 0x3f7fffff, v1
+; GFX7-NEXT: v_cmp_u_f32_e32 vcc, v0, v0
+; GFX7-NEXT: v_cndmask_b32_e32 v0, v1, v0, vcc
; GFX7-NEXT: s_setpc_b64 s[30:31]
-; GFX8-LABEL: safe_math_fract_f64_noinf_check:
+;
+; GFX8-LABEL: select_nan_fract_f32_ninf_minnum:
; GFX8: ; %bb.0: ; %entry
; GFX8-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX8-NEXT: v_floor_f64_e32 v[4:5], v[0:1]
-; GFX8-NEXT: v_fract_f64_e32 v[0:1], v[0:1]
-; GFX8-NEXT: global_store_dwordx2 v[2:3], v[4:5], off
-; GFX8-NEXT: s_waitcnt vmcnt(0)
+; GFX8-NEXT: v_floor_f32_e32 v1, v0
+; GFX8-NEXT: v_sub_f32_e32 v1, v0, v1
+; GFX8-NEXT: v_min_f32_e32 v1, 0x3f7fffff, v1
+; GFX8-NEXT: v_cmp_u_f32_e32 vcc, v0, v0
+; GFX8-NEXT: v_cndmask_b32_e32 v0, v1, v0, vcc
; GFX8-NEXT: s_setpc_b64 s[30:31]
-; GFX11-LABEL: safe_math_fract_f64_noinf_check:
+;
+; GFX11-LABEL: select_nan_fract_f32_ninf_minnum:
; GFX11: ; %bb.0: ; %entry
; GFX11-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX11-NEXT: v_floor_f64_e32 v[4:5], v[0:1]
-; GFX11-NEXT: v_fract_f64_e32 v[0:1], v[0:1]
-; GFX11-NEXT: global_store_b64 v[2:3], v[4:5], off
+; GFX11-NEXT: v_floor_f32_e32 v1, v0
+; GFX11-NEXT: v_cmp_u_f32_e32 vcc_lo, v0, v0
+; GFX11-NEXT: s_delay_alu instid0(VALU_DEP_2) | instskip(NEXT) | instid1(VALU_DEP_1)
+; GFX11-NEXT: v_sub_f32_e32 v1, v0, v1
+; GFX11-NEXT: v_min_f32_e32 v1, 0x3f7fffff, v1
+; GFX11-NEXT: s_delay_alu instid0(VALU_DEP_1)
+; GFX11-NEXT: v_cndmask_b32_e32 v0, v1, v0, vcc_lo
; GFX11-NEXT: s_setpc_b64 s[30:31]
-; GFX12-LABEL: safe_math_fract_f64_noinf_check:
+;
+; GFX12-LABEL: select_nan_fract_f32_ninf_minnum:
; GFX12: ; %bb.0: ; %entry
; GFX12-NEXT: s_wait_loadcnt_dscnt 0x0
; GFX12-NEXT: s_wait_expcnt 0x0
; GFX12-NEXT: s_wait_samplecnt 0x0
; GFX12-NEXT: s_wait_bvhcnt 0x0
; GFX12-NEXT: s_wait_kmcnt 0x0
-; GFX12-NEXT: v_floor_f64_e32 v[4:5], v[0:1]
-; GFX12-NEXT: v_fract_f64_e32 v[0:1], v[0:1]
-; GFX12-NEXT: global_store_b64 v[2:3], v[4:5], off
+; GFX12-NEXT: v_floor_f32_e32 v1, v0
+; GFX12-NEXT: v_cmp_u_f32_e32 vcc_lo, v0, v0
+; GFX12-NEXT: s_delay_alu instid0(VALU_DEP_2) | instskip(NEXT) | instid1(VALU_DEP_1)
+; GFX12-NEXT: v_sub_f32_e32 v1, v0, v1
+; GFX12-NEXT: v_min_num_f32_e32 v1, 0x3f7fffff, v1
+; GFX12-NEXT: s_wait_alu depctr_va_vcc(0)
+; GFX12-NEXT: s_delay_alu instid0(VALU_DEP_1)
+; GFX12-NEXT: v_cndmask_b32_e32 v0, v1, v0, vcc_lo
; GFX12-NEXT: s_setpc_b64 s[30:31]
entry:
- %floor = tail call double @llvm.floor.f64(double %x)
- %sub = fsub double %x, %floor
- %min = tail call double @llvm.minnum.f64(double %sub, double 0x3FEFFFFFFFFFFFFF)
- %uno = fcmp uno double %x, 0.000000e+00
- %cond = select i1 %uno, double %x, double %min
- store double %floor, ptr addrspace(1) %ip, align 4
- ret double %cond
+ %floor = tail call float @llvm.floor.f32(float %x)
+ %sub = fsub float %x, %floor
+ %min = tail call ninf float @llvm.minnum.f32(float %sub, float 0x3FEFFFFFE0000000)
+ %uno = fcmp uno float %x, 0.000000e+00
+ %cond = select i1 %uno, float %x, float %min
+ ret float %cond
}
-define float @select_nan_fract_f32_flags_select(float %x) {
-; GFX6-IR-LABEL: define float @select_nan_fract_f32_flags_select(
+define float @select_nan_fract_f32_ninf_fsub(float %x) {
+; GFX6-IR-LABEL: define float @select_nan_fract_f32_ninf_fsub(
; GFX6-IR-SAME: float [[X:%.*]]) {
; GFX6-IR-NEXT: [[ENTRY:.*:]]
; GFX6-IR-NEXT: [[FLOOR:%.*]] = tail call float @llvm.floor.f32(float [[X]])
-; GFX6-IR-NEXT: [[SUB:%.*]] = fsub float [[X]], [[FLOOR]]
+; GFX6-IR-NEXT: [[SUB:%.*]] = fsub ninf float [[X]], [[FLOOR]]
; GFX6-IR-NEXT: [[MIN:%.*]] = tail call float @llvm.minnum.f32(float [[SUB]], float f0x3F7FFFFF)
; GFX6-IR-NEXT: [[UNO:%.*]] = fcmp uno float [[X]], 0.000000e+00
-; GFX6-IR-NEXT: [[COND:%.*]] = select nsz i1 [[UNO]], float [[X]], float [[MIN]]
+; GFX6-IR-NEXT: [[COND:%.*]] = select i1 [[UNO]], float [[X]], float [[MIN]]
; GFX6-IR-NEXT: ret float [[COND]]
;
-; IR-FRACT-LABEL: define float @select_nan_fract_f32_flags_select(
+; IR-FRACT-LABEL: define float @select_nan_fract_f32_ninf_fsub(
; IR-FRACT-SAME: float [[X:%.*]]) {
; IR-FRACT-NEXT: [[ENTRY:.*:]]
-; IR-FRACT-NEXT: [[COND:%.*]] = call nsz float @llvm.amdgcn.fract.f32(float [[X]])
+; IR-FRACT-NEXT: [[COND:%.*]] = call float @llvm.amdgcn.fract.f32(float [[X]])
; IR-FRACT-NEXT: ret float [[COND]]
;
-; GFX6-LABEL: select_nan_fract_f32_flags_select:
+; GFX6-LABEL: select_nan_fract_f32_ninf_fsub:
; GFX6: ; %bb.0: ; %entry
; GFX6-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
; GFX6-NEXT: v_floor_f32_e32 v1, v0
@@ -2281,22 +2877,26 @@ define float @select_nan_fract_f32_flags_select(float %x) {
; GFX6-NEXT: v_cmp_u_f32_e32 vcc, v0, v0
; GFX6-NEXT: v_cndmask_b32_e32 v0, v1, v0, vcc
; GFX6-NEXT: s_setpc_b64 s[30:31]
-; GFX7-LABEL: select_nan_fract_f32_flags_select:
+;
+; GFX7-LABEL: select_nan_fract_f32_ninf_fsub:
; GFX7: ; %bb.0: ; %entry
; GFX7-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
; GFX7-NEXT: v_fract_f32_e32 v0, v0
; GFX7-NEXT: s_setpc_b64 s[30:31]
-; GFX8-LABEL: select_nan_fract_f32_flags_select:
+;
+; GFX8-LABEL: select_nan_fract_f32_ninf_fsub:
; GFX8: ; %bb.0: ; %entry
; GFX8-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
; GFX8-NEXT: v_fract_f32_e32 v0, v0
; GFX8-NEXT: s_setpc_b64 s[30:31]
-; GFX11-LABEL: select_nan_fract_f32_flags_select:
+;
+; GFX11-LABEL: select_nan_fract_f32_ninf_fsub:
; GFX11: ; %bb.0: ; %entry
; GFX11-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
; GFX11-NEXT: v_fract_f32_e32 v0, v0
; GFX11-NEXT: s_setpc_b64 s[30:31]
-; GFX12-LABEL: select_nan_fract_f32_flags_select:
+;
+; GFX12-LABEL: select_nan_fract_f32_ninf_fsub:
; GFX12: ; %bb.0: ; %entry
; GFX12-NEXT: s_wait_loadcnt_dscnt 0x0
; GFX12-NEXT: s_wait_expcnt 0x0
@@ -2307,70 +2907,107 @@ define float @select_nan_fract_f32_flags_select(float %x) {
; GFX12-NEXT: s_setpc_b64 s[30:31]
entry:
%floor = tail call float @llvm.floor.f32(float %x)
- %sub = fsub float %x, %floor
+ %sub = fsub ninf float %x, %floor
%min = tail call float @llvm.minnum.f32(float %sub, float 0x3FEFFFFFE0000000)
%uno = fcmp uno float %x, 0.000000e+00
- %cond = select nsz i1 %uno, float %x, float %min
+ %cond = select i1 %uno, float %x, float %min
ret float %cond
}
-define float @select_nan_fract_f32_flags_minnum(float %x) {
-; GFX6-IR-LABEL: define float @select_nan_fract_f32_flags_minnum(
-; GFX6-IR-SAME: float [[X:%.*]]) {
-; GFX6-IR-NEXT: [[ENTRY:.*:]]
-; GFX6-IR-NEXT: [[FLOOR:%.*]] = tail call float @llvm.floor.f32(float [[X]])
-; GFX6-IR-NEXT: [[SUB:%.*]] = fsub float [[X]], [[FLOOR]]
-; GFX6-IR-NEXT: [[MIN:%.*]] = tail call nsz float @llvm.minnum.f32(float [[SUB]], float f0x3F7FFFFF)
-; GFX6-IR-NEXT: [[UNO:%.*]] = fcmp uno float [[X]], 0.000000e+00
-; GFX6-IR-NEXT: [[COND:%.*]] = select i1 [[UNO]], float [[X]], float [[MIN]]
-; GFX6-IR-NEXT: ret float [[COND]]
-;
-; IR-FRACT-LABEL: define float @select_nan_fract_f32_flags_minnum(
-; IR-FRACT-SAME: float [[X:%.*]]) {
-; IR-FRACT-NEXT: [[ENTRY:.*:]]
-; IR-FRACT-NEXT: [[COND:%.*]] = call float @llvm.amdgcn.fract.f32(float [[X]])
-; IR-FRACT-NEXT: ret float [[COND]]
+define float @select_nan_fract_f32_inf_check_posinf_only(float %x) {
+; IR-LABEL: define float @select_nan_fract_f32_inf_check_posinf_only(
+; IR-SAME: float [[X:%.*]]) {
+; IR-NEXT: [[ENTRY:.*:]]
+; IR-NEXT: [[FLOOR:%.*]] = tail call float @llvm.floor.f32(float [[X]])
+; IR-NEXT: [[SUB:%.*]] = fsub float [[X]], [[FLOOR]]
+; IR-NEXT: [[MIN:%.*]] = tail call float @llvm.minnum.f32(float [[SUB]], float f0x3F7FFFFF)
+; IR-NEXT: [[UNO:%.*]] = fcmp uno float [[X]], 0.000000e+00
+; IR-NEXT: [[SEL:%.*]] = select i1 [[UNO]], float [[X]], float [[MIN]]
+; IR-NEXT: [[ISINF:%.*]] = fcmp oeq float [[X]], +inf
+; IR-NEXT: [[RET:%.*]] = select i1 [[ISINF]], float 0.000000e+00, float [[SEL]]
+; IR-NEXT: ret float [[RET]]
;
-; GFX6-LABEL: select_nan_fract_f32_flags_minnum:
+; GFX6-LABEL: select_nan_fract_f32_inf_check_posinf_only:
; GFX6: ; %bb.0: ; %entry
; GFX6-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
; GFX6-NEXT: v_floor_f32_e32 v1, v0
; GFX6-NEXT: v_sub_f32_e32 v1, v0, v1
; GFX6-NEXT: v_min_f32_e32 v1, 0x3f7fffff, v1
; GFX6-NEXT: v_cmp_u_f32_e32 vcc, v0, v0
-; GFX6-NEXT: v_cndmask_b32_e32 v0, v1, v0, vcc
+; GFX6-NEXT: s_mov_b32 s4, 0x7f800000
+; GFX6-NEXT: v_cndmask_b32_e32 v1, v1, v0, vcc
+; GFX6-NEXT: v_cmp_neq_f32_e32 vcc, s4, v0
+; GFX6-NEXT: v_cndmask_b32_e32 v0, 0, v1, vcc
; GFX6-NEXT: s_setpc_b64 s[30:31]
-; GFX7-LABEL: select_nan_fract_f32_flags_minnum:
+;
+; GFX7-LABEL: select_nan_fract_f32_inf_check_posinf_only:
; GFX7: ; %bb.0: ; %entry
; GFX7-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX7-NEXT: v_fract_f32_e32 v0, v0
+; GFX7-NEXT: v_floor_f32_e32 v1, v0
+; GFX7-NEXT: v_sub_f32_e32 v1, v0, v1
+; GFX7-NEXT: v_min_f32_e32 v1, 0x3f7fffff, v1
+; GFX7-NEXT: v_cmp_u_f32_e32 vcc, v0, v0
+; GFX7-NEXT: s_mov_b32 s4, 0x7f800000
+; GFX7-NEXT: v_cndmask_b32_e32 v1, v1, v0, vcc
+; GFX7-NEXT: v_cmp_neq_f32_e32 vcc, s4, v0
+; GFX7-NEXT: v_cndmask_b32_e32 v0, 0, v1, vcc
; GFX7-NEXT: s_setpc_b64 s[30:31]
-; GFX8-LABEL: select_nan_fract_f32_flags_minnum:
+;
+; GFX8-LABEL: select_nan_fract_f32_inf_check_posinf_only:
; GFX8: ; %bb.0: ; %entry
; GFX8-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX8-NEXT: v_fract_f32_e32 v0, v0
+; GFX8-NEXT: v_floor_f32_e32 v1, v0
+; GFX8-NEXT: v_sub_f32_e32 v1, v0, v1
+; GFX8-NEXT: v_min_f32_e32 v1, 0x3f7fffff, v1
+; GFX8-NEXT: v_cmp_u_f32_e32 vcc, v0, v0
+; GFX8-NEXT: s_mov_b32 s4, 0x7f800000
+; GFX8-NEXT: v_cndmask_b32_e32 v1, v1, v0, vcc
+; GFX8-NEXT: v_cmp_neq_f32_e32 vcc, s4, v0
+; GFX8-NEXT: v_cndmask_b32_e32 v0, 0, v1, vcc
; GFX8-NEXT: s_setpc_b64 s[30:31]
-; GFX11-LABEL: select_nan_fract_f32_flags_minnum:
+;
+; GFX11-LABEL: select_nan_fract_f32_inf_check_posinf_only:
; GFX11: ; %bb.0: ; %entry
; GFX11-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX11-NEXT: v_fract_f32_e32 v0, v0
+; GFX11-NEXT: v_floor_f32_e32 v1, v0
+; GFX11-NEXT: v_cmp_u_f32_e32 vcc_lo, v0, v0
+; GFX11-NEXT: s_delay_alu instid0(VALU_DEP_2) | instskip(NEXT) | instid1(VALU_DEP_1)
+; GFX11-NEXT: v_sub_f32_e32 v1, v0, v1
+; GFX11-NEXT: v_min_f32_e32 v1, 0x3f7fffff, v1
+; GFX11-NEXT: s_delay_alu instid0(VALU_DEP_1) | instskip(SKIP_1) | instid1(VALU_DEP_2)
+; GFX11-NEXT: v_cndmask_b32_e32 v1, v1, v0, vcc_lo
+; GFX11-NEXT: v_cmp_neq_f32_e32 vcc_lo, 0x7f800000, v0
+; GFX11-NEXT: v_cndmask_b32_e32 v0, 0, v1, vcc_lo
; GFX11-NEXT: s_setpc_b64 s[30:31]
-; GFX12-LABEL: select_nan_fract_f32_flags_minnum:
+;
+; GFX12-LABEL: select_nan_fract_f32_inf_check_posinf_only:
; GFX12: ; %bb.0: ; %entry
; GFX12-NEXT: s_wait_loadcnt_dscnt 0x0
; GFX12-NEXT: s_wait_expcnt 0x0
; GFX12-NEXT: s_wait_samplecnt 0x0
; GFX12-NEXT: s_wait_bvhcnt 0x0
; GFX12-NEXT: s_wait_kmcnt 0x0
-; GFX12-NEXT: v_fract_f32_e32 v0, v0
+; GFX12-NEXT: v_floor_f32_e32 v1, v0
+; GFX12-NEXT: v_cmp_u_f32_e32 vcc_lo, v0, v0
+; GFX12-NEXT: s_delay_alu instid0(VALU_DEP_2) | instskip(NEXT) | instid1(VALU_DEP_1)
+; GFX12-NEXT: v_sub_f32_e32 v1, v0, v1
+; GFX12-NEXT: v_min_num_f32_e32 v1, 0x3f7fffff, v1
+; GFX12-NEXT: s_wait_alu depctr_va_vcc(0)
+; GFX12-NEXT: s_delay_alu instid0(VALU_DEP_1) | instskip(SKIP_2) | instid1(VALU_DEP_2)
+; GFX12-NEXT: v_cndmask_b32_e32 v1, v1, v0, vcc_lo
+; GFX12-NEXT: v_cmp_neq_f32_e32 vcc_lo, 0x7f800000, v0
+; GFX12-NEXT: s_wait_alu depctr_va_vcc(0)
+; GFX12-NEXT: v_cndmask_b32_e32 v0, 0, v1, vcc_lo
; GFX12-NEXT: s_setpc_b64 s[30:31]
entry:
%floor = tail call float @llvm.floor.f32(float %x)
%sub = fsub float %x, %floor
- %min = tail call nsz float @llvm.minnum.f32(float %sub, float 0x3FEFFFFFE0000000)
+ %min = tail call float @llvm.minnum.f32(float %sub, float 0x3FEFFFFFE0000000)
%uno = fcmp uno float %x, 0.000000e+00
- %cond = select i1 %uno, float %x, float %min
- ret float %cond
+ %sel = select i1 %uno, float %x, float %min
+ %isinf = fcmp oeq float %x, 0x7FF0000000000000
+ %ret = select i1 %isinf, float 0.000000e+00, float %sel
+ ret float %ret
}
define <2 x float> @safe_math_fract_v2f32(<2 x float> %x, ptr addrspace(1) writeonly captures(none) %ip) {
@@ -3638,19 +4275,13 @@ entry:
}
define float @basic_fract_f32_nonans_minimumnum(float nofpclass(nan) %x) {
-; GFX6-IR-LABEL: define float @basic_fract_f32_nonans_minimumnum(
-; GFX6-IR-SAME: float nofpclass(nan) [[X:%.*]]) {
-; GFX6-IR-NEXT: [[ENTRY:.*:]]
-; GFX6-IR-NEXT: [[FLOOR:%.*]] = tail call float @llvm.floor.f32(float [[X]])
-; GFX6-IR-NEXT: [[SUB:%.*]] = fsub float [[X]], [[FLOOR]]
-; GFX6-IR-NEXT: [[MIN:%.*]] = tail call float @llvm.minimumnum.f32(float [[SUB]], float f0x3F7FFFFF)
-; GFX6-IR-NEXT: ret float [[MIN]]
-;
-; IR-FRACT-LABEL: define float @basic_fract_f32_nonans_minimumnum(
-; IR-FRACT-SAME: float nofpclass(nan) [[X:%.*]]) {
-; IR-FRACT-NEXT: [[ENTRY:.*:]]
-; IR-FRACT-NEXT: [[MIN:%.*]] = call nnan float @llvm.amdgcn.fract.f32(float [[X]])
-; IR-FRACT-NEXT: ret float [[MIN]]
+; IR-LABEL: define float @basic_fract_f32_nonans_minimumnum(
+; IR-SAME: float nofpclass(nan) [[X:%.*]]) {
+; IR-NEXT: [[ENTRY:.*:]]
+; IR-NEXT: [[FLOOR:%.*]] = tail call float @llvm.floor.f32(float [[X]])
+; IR-NEXT: [[SUB:%.*]] = fsub float [[X]], [[FLOOR]]
+; IR-NEXT: [[MIN:%.*]] = tail call float @llvm.minimumnum.f32(float [[SUB]], float f0x3F7FFFFF)
+; IR-NEXT: ret float [[MIN]]
;
; GFX6-LABEL: basic_fract_f32_nonans_minimumnum:
; GFX6: ; %bb.0: ; %entry
@@ -3659,21 +4290,32 @@ define float @basic_fract_f32_nonans_minimumnum(float nofpclass(nan) %x) {
; GFX6-NEXT: v_sub_f32_e32 v0, v0, v1
; GFX6-NEXT: v_min_f32_e32 v0, 0x3f7fffff, v0
; GFX6-NEXT: s_setpc_b64 s[30:31]
+;
; GFX7-LABEL: basic_fract_f32_nonans_minimumnum:
; GFX7: ; %bb.0: ; %entry
; GFX7-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX7-NEXT: v_fract_f32_e32 v0, v0
+; GFX7-NEXT: v_floor_f32_e32 v1, v0
+; GFX7-NEXT: v_sub_f32_e32 v0, v0, v1
+; GFX7-NEXT: v_min_f32_e32 v0, 0x3f7fffff, v0
; GFX7-NEXT: s_setpc_b64 s[30:31]
+;
; GFX8-LABEL: basic_fract_f32_nonans_minimumnum:
; GFX8: ; %bb.0: ; %entry
; GFX8-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX8-NEXT: v_fract_f32_e32 v0, v0
+; GFX8-NEXT: v_floor_f32_e32 v1, v0
+; GFX8-NEXT: v_sub_f32_e32 v0, v0, v1
+; GFX8-NEXT: v_min_f32_e32 v0, 0x3f7fffff, v0
; GFX8-NEXT: s_setpc_b64 s[30:31]
+;
; GFX11-LABEL: basic_fract_f32_nonans_minimumnum:
; GFX11: ; %bb.0: ; %entry
; GFX11-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX11-NEXT: v_fract_f32_e32 v0, v0
+; GFX11-NEXT: v_floor_f32_e32 v1, v0
+; GFX11-NEXT: s_delay_alu instid0(VALU_DEP_1) | instskip(NEXT) | instid1(VALU_DEP_1)
+; GFX11-NEXT: v_sub_f32_e32 v0, v0, v1
+; GFX11-NEXT: v_min_f32_e32 v0, 0x3f7fffff, v0
; GFX11-NEXT: s_setpc_b64 s[30:31]
+;
; GFX12-LABEL: basic_fract_f32_nonans_minimumnum:
; GFX12: ; %bb.0: ; %entry
; GFX12-NEXT: s_wait_loadcnt_dscnt 0x0
@@ -3681,7 +4323,10 @@ define float @basic_fract_f32_nonans_minimumnum(float nofpclass(nan) %x) {
; GFX12-NEXT: s_wait_samplecnt 0x0
; GFX12-NEXT: s_wait_bvhcnt 0x0
; GFX12-NEXT: s_wait_kmcnt 0x0
-; GFX12-NEXT: v_fract_f32_e32 v0, v0
+; GFX12-NEXT: v_floor_f32_e32 v1, v0
+; GFX12-NEXT: s_delay_alu instid0(VALU_DEP_1) | instskip(NEXT) | instid1(VALU_DEP_1)
+; GFX12-NEXT: v_sub_f32_e32 v0, v0, v1
+; GFX12-NEXT: v_min_num_f32_e32 v0, 0x3f7fffff, v0
; GFX12-NEXT: s_setpc_b64 s[30:31]
entry:
%floor = tail call float @llvm.floor.f32(float %x)
@@ -4781,21 +5426,39 @@ define float @safe_math_fract_f32_swapped_edge_case_cmp_neg_inf(float %x) #0 {
; GFX6-NEXT: v_cmp_o_f32_e32 vcc, v0, v0
; GFX6-NEXT: v_cndmask_b32_e32 v0, v0, v1, vcc
; GFX6-NEXT: s_setpc_b64 s[30:31]
+;
; GFX7-LABEL: safe_math_fract_f32_swapped_edge_case_cmp_neg_inf:
; GFX7: ; %bb.0: ; %entry
; GFX7-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX7-NEXT: v_fract_f32_e32 v0, v0
+; GFX7-NEXT: v_floor_f32_e32 v1, v0
+; GFX7-NEXT: v_sub_f32_e32 v1, v0, v1
+; GFX7-NEXT: v_min_f32_e32 v1, 0x3f7fffff, v1
+; GFX7-NEXT: v_cmp_o_f32_e32 vcc, v0, v0
+; GFX7-NEXT: v_cndmask_b32_e32 v0, v0, v1, vcc
; GFX7-NEXT: s_setpc_b64 s[30:31]
+;
; GFX8-LABEL: safe_math_fract_f32_swapped_edge_case_cmp_neg_inf:
; GFX8: ; %bb.0: ; %entry
; GFX8-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX8-NEXT: v_fract_f32_e32 v0, v0
+; GFX8-NEXT: v_floor_f32_e32 v1, v0
+; GFX8-NEXT: v_sub_f32_e32 v1, v0, v1
+; GFX8-NEXT: v_min_f32_e32 v1, 0x3f7fffff, v1
+; GFX8-NEXT: v_cmp_o_f32_e32 vcc, v0, v0
+; GFX8-NEXT: v_cndmask_b32_e32 v0, v0, v1, vcc
; GFX8-NEXT: s_setpc_b64 s[30:31]
+;
; GFX11-LABEL: safe_math_fract_f32_swapped_edge_case_cmp_neg_inf:
; GFX11: ; %bb.0: ; %entry
; GFX11-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX11-NEXT: v_fract_f32_e32 v0, v0
+; GFX11-NEXT: v_floor_f32_e32 v1, v0
+; GFX11-NEXT: v_cmp_o_f32_e32 vcc_lo, v0, v0
+; GFX11-NEXT: s_delay_alu instid0(VALU_DEP_2) | instskip(NEXT) | instid1(VALU_DEP_1)
+; GFX11-NEXT: v_sub_f32_e32 v1, v0, v1
+; GFX11-NEXT: v_min_f32_e32 v1, 0x3f7fffff, v1
+; GFX11-NEXT: s_delay_alu instid0(VALU_DEP_1)
+; GFX11-NEXT: v_cndmask_b32_e32 v0, v0, v1, vcc_lo
; GFX11-NEXT: s_setpc_b64 s[30:31]
+;
; GFX12-LABEL: safe_math_fract_f32_swapped_edge_case_cmp_neg_inf:
; GFX12: ; %bb.0: ; %entry
; GFX12-NEXT: s_wait_loadcnt_dscnt 0x0
@@ -4803,7 +5466,14 @@ define float @safe_math_fract_f32_swapped_edge_case_cmp_neg_inf(float %x) #0 {
; GFX12-NEXT: s_wait_samplecnt 0x0
; GFX12-NEXT: s_wait_bvhcnt 0x0
; GFX12-NEXT: s_wait_kmcnt 0x0
-; GFX12-NEXT: v_fract_f32_e32 v0, v0
+; GFX12-NEXT: v_floor_f32_e32 v1, v0
+; GFX12-NEXT: v_cmp_o_f32_e32 vcc_lo, v0, v0
+; GFX12-NEXT: s_delay_alu instid0(VALU_DEP_2) | instskip(NEXT) | instid1(VALU_DEP_1)
+; GFX12-NEXT: v_sub_f32_e32 v1, v0, v1
+; GFX12-NEXT: v_min_num_f32_e32 v1, 0x3f7fffff, v1
+; GFX12-NEXT: s_wait_alu depctr_va_vcc(0)
+; GFX12-NEXT: s_delay_alu instid0(VALU_DEP_1)
+; GFX12-NEXT: v_cndmask_b32_e32 v0, v0, v1, vcc_lo
; GFX12-NEXT: s_setpc_b64 s[30:31]
entry:
%floor = call float @llvm.floor.f32(float %x) #3
@@ -5156,22 +5826,22 @@ define float @safe_math_fract_f32_swapped_edge_case_split_block(float %x, i1 %co
; GFX11-NEXT: ; implicit-def: $vgpr0
; GFX11-NEXT: s_and_saveexec_b32 s0, vcc_lo
; GFX11-NEXT: s_xor_b32 s0, exec_lo, s0
-; GFX11-NEXT: s_cbranch_execnz .LBB58_3
+; GFX11-NEXT: s_cbranch_execnz .LBB65_3
; GFX11-NEXT: ; %bb.1: ; %Flow
; GFX11-NEXT: s_and_not1_saveexec_b32 s0, s0
-; GFX11-NEXT: s_cbranch_execnz .LBB58_4
-; GFX11-NEXT: .LBB58_2: ; %UnifiedReturnBlock
+; GFX11-NEXT: s_cbranch_execnz .LBB65_4
+; GFX11-NEXT: .LBB65_2: ; %UnifiedReturnBlock
; GFX11-NEXT: s_or_b32 exec_lo, exec_lo, s0
; GFX11-NEXT: s_setpc_b64 s[30:31]
-; GFX11-NEXT: .LBB58_3: ; %ret
+; GFX11-NEXT: .LBB65_3: ; %ret
; GFX11-NEXT: v_floor_f32_e32 v0, v2
; GFX11-NEXT: s_delay_alu instid0(VALU_DEP_1) | instskip(NEXT) | instid1(VALU_DEP_1)
; GFX11-NEXT: v_sub_f32_e32 v0, v2, v0
; GFX11-NEXT: ; implicit-def: $vgpr2
; GFX11-NEXT: v_min_f32_e32 v0, 0x3f7fffff, v0
; GFX11-NEXT: s_and_not1_saveexec_b32 s0, s0
-; GFX11-NEXT: s_cbranch_execz .LBB58_2
-; GFX11-NEXT: .LBB58_4: ; %edge_cases
+; GFX11-NEXT: s_cbranch_execz .LBB65_2
+; GFX11-NEXT: .LBB65_4: ; %edge_cases
; GFX11-NEXT: v_fract_f32_e32 v0, v2
; GFX11-NEXT: v_cmp_neq_f32_e64 vcc_lo, 0x7f800000, |v2|
; GFX11-NEXT: s_delay_alu instid0(VALU_DEP_2)
@@ -5194,16 +5864,16 @@ define float @safe_math_fract_f32_swapped_edge_case_split_block(float %x, i1 %co
; GFX12-NEXT: s_and_saveexec_b32 s0, vcc_lo
; GFX12-NEXT: s_wait_alu depctr_sa_sdst(0)
; GFX12-NEXT: s_xor_b32 s0, exec_lo, s0
-; GFX12-NEXT: s_cbranch_execnz .LBB58_3
+; GFX12-NEXT: s_cbranch_execnz .LBB65_3
; GFX12-NEXT: ; %bb.1: ; %Flow
; GFX12-NEXT: s_wait_alu depctr_sa_sdst(0)
; GFX12-NEXT: s_and_not1_saveexec_b32 s0, s0
-; GFX12-NEXT: s_cbranch_execnz .LBB58_4
-; GFX12-NEXT: .LBB58_2: ; %UnifiedReturnBlock
+; GFX12-NEXT: s_cbranch_execnz .LBB65_4
+; GFX12-NEXT: .LBB65_2: ; %UnifiedReturnBlock
; GFX12-NEXT: s_wait_alu depctr_sa_sdst(0)
; GFX12-NEXT: s_or_b32 exec_lo, exec_lo, s0
; GFX12-NEXT: s_setpc_b64 s[30:31]
-; GFX12-NEXT: .LBB58_3: ; %ret
+; GFX12-NEXT: .LBB65_3: ; %ret
; GFX12-NEXT: v_floor_f32_e32 v0, v2
; GFX12-NEXT: s_delay_alu instid0(VALU_DEP_1) | instskip(NEXT) | instid1(VALU_DEP_1)
; GFX12-NEXT: v_sub_f32_e32 v0, v2, v0
@@ -5211,8 +5881,8 @@ define float @safe_math_fract_f32_swapped_edge_case_split_block(float %x, i1 %co
; GFX12-NEXT: v_min_num_f32_e32 v0, 0x3f7fffff, v0
; GFX12-NEXT: s_wait_alu depctr_sa_sdst(0)
; GFX12-NEXT: s_and_not1_saveexec_b32 s0, s0
-; GFX12-NEXT: s_cbranch_execz .LBB58_2
-; GFX12-NEXT: .LBB58_4: ; %edge_cases
+; GFX12-NEXT: s_cbranch_execz .LBB65_2
+; GFX12-NEXT: .LBB65_4: ; %edge_cases
; GFX12-NEXT: v_fract_f32_e32 v0, v2
; GFX12-NEXT: v_cmp_neq_f32_e64 vcc_lo, 0x7f800000, |v2|
; GFX12-NEXT: s_wait_alu depctr_va_vcc(0)
@@ -5236,7 +5906,6 @@ define float @safe_math_fract_f32_swapped_edge_case_split_block(float %x, i1 %co
; GFX6-IR-NEXT: ret float [[COND8]]
; GFX6-IR: [[RET]]:
; GFX6-IR-NEXT: ret float [[MIN]]
-;
; IR-FRACT-LABEL: define float @safe_math_fract_f32_swapped_edge_case_split_block(
; IR-FRACT-SAME: float [[X:%.*]], i1 [[COND:%.*]]) #[[ATTR0]] {
; IR-FRACT-NEXT: [[FLOOR:%.*]] = call float @llvm.floor.f32(float [[X]])
@@ -5251,7 +5920,6 @@ define float @safe_math_fract_f32_swapped_edge_case_split_block(float %x, i1 %co
; IR-FRACT-NEXT: ret float [[COND8]]
; IR-FRACT: [[RET]]:
; IR-FRACT-NEXT: ret float [[MIN]]
-;
%floor = call float @llvm.floor.f32(float %x)
%sub = fsub float %x, %floor
%min = call float @llvm.minnum.f32(float %sub, float 0x3FEFFFFFE0000000)
@@ -5402,19 +6070,33 @@ define float @safe_math_fract_f32_swapped_edge_case_inf_check_wrong_compare(floa
; GFX7-LABEL: safe_math_fract_f32_swapped_edge_case_inf_check_wrong_compare:
; GFX7: ; %bb.0: ; %entry
; GFX7-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX7-NEXT: v_fract_f32_e32 v0, v0
+; GFX7-NEXT: v_floor_f32_e32 v1, v0
+; GFX7-NEXT: v_sub_f32_e32 v1, v0, v1
+; GFX7-NEXT: v_min_f32_e32 v1, 0x3f7fffff, v1
+; GFX7-NEXT: v_cmp_o_f32_e32 vcc, v0, v0
+; GFX7-NEXT: v_cndmask_b32_e32 v0, v0, v1, vcc
; GFX7-NEXT: s_setpc_b64 s[30:31]
;
; GFX8-LABEL: safe_math_fract_f32_swapped_edge_case_inf_check_wrong_compare:
; GFX8: ; %bb.0: ; %entry
; GFX8-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX8-NEXT: v_fract_f32_e32 v0, v0
+; GFX8-NEXT: v_floor_f32_e32 v1, v0
+; GFX8-NEXT: v_sub_f32_e32 v1, v0, v1
+; GFX8-NEXT: v_min_f32_e32 v1, 0x3f7fffff, v1
+; GFX8-NEXT: v_cmp_o_f32_e32 vcc, v0, v0
+; GFX8-NEXT: v_cndmask_b32_e32 v0, v0, v1, vcc
; GFX8-NEXT: s_setpc_b64 s[30:31]
;
; GFX11-LABEL: safe_math_fract_f32_swapped_edge_case_inf_check_wrong_compare:
; GFX11: ; %bb.0: ; %entry
; GFX11-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX11-NEXT: v_fract_f32_e32 v0, v0
+; GFX11-NEXT: v_floor_f32_e32 v1, v0
+; GFX11-NEXT: v_cmp_o_f32_e32 vcc_lo, v0, v0
+; GFX11-NEXT: s_delay_alu instid0(VALU_DEP_2) | instskip(NEXT) | instid1(VALU_DEP_1)
+; GFX11-NEXT: v_sub_f32_e32 v1, v0, v1
+; GFX11-NEXT: v_min_f32_e32 v1, 0x3f7fffff, v1
+; GFX11-NEXT: s_delay_alu instid0(VALU_DEP_1)
+; GFX11-NEXT: v_cndmask_b32_e32 v0, v0, v1, vcc_lo
; GFX11-NEXT: s_setpc_b64 s[30:31]
;
; GFX12-LABEL: safe_math_fract_f32_swapped_edge_case_inf_check_wrong_compare:
@@ -5424,7 +6106,14 @@ define float @safe_math_fract_f32_swapped_edge_case_inf_check_wrong_compare(floa
; GFX12-NEXT: s_wait_samplecnt 0x0
; GFX12-NEXT: s_wait_bvhcnt 0x0
; GFX12-NEXT: s_wait_kmcnt 0x0
-; GFX12-NEXT: v_fract_f32_e32 v0, v0
+; GFX12-NEXT: v_floor_f32_e32 v1, v0
+; GFX12-NEXT: v_cmp_o_f32_e32 vcc_lo, v0, v0
+; GFX12-NEXT: s_delay_alu instid0(VALU_DEP_2) | instskip(NEXT) | instid1(VALU_DEP_1)
+; GFX12-NEXT: v_sub_f32_e32 v1, v0, v1
+; GFX12-NEXT: v_min_num_f32_e32 v1, 0x3f7fffff, v1
+; GFX12-NEXT: s_wait_alu depctr_va_vcc(0)
+; GFX12-NEXT: s_delay_alu instid0(VALU_DEP_1)
+; GFX12-NEXT: v_cndmask_b32_e32 v0, v0, v1, vcc_lo
; GFX12-NEXT: s_setpc_b64 s[30:31]
; IR-LABEL: define float @safe_math_fract_f32_swapped_edge_case_inf_check_wrong_compare(
; IR-SAME: float [[X:%.*]]) #[[ATTR0]] {
@@ -5438,7 +6127,6 @@ define float @safe_math_fract_f32_swapped_edge_case_inf_check_wrong_compare(floa
; IR-NEXT: [[NOT_NAN:%.*]] = fcmp ord float [[X]], 0.000000e+00
; IR-NEXT: [[COND8:%.*]] = select i1 [[NOT_NAN]], float [[COND]], float [[X]]
; IR-NEXT: ret float [[COND8]]
-;
entry:
%floor = call float @llvm.floor.f32(float %x)
%sub = fsub float %x, %floor
More information about the llvm-commits
mailing list