[llvm] [SelectionDAG] Add expansion for llvm.modf intrinsic (PR #179434)

Alex Wang via llvm-commits llvm-commits at lists.llvm.org
Tue Feb 3 03:08:36 PST 2026


https://github.com/aeft created https://github.com/llvm/llvm-project/pull/179434

This PR enables targets without a modf libcall to use the intrinsic instead of a library call. Targets with an available modf libcall will continue using the libcall.

Following the same pattern as the existing `llvm.frexp` expansion.

I would appreciate the reviewers' feedback on several questions:
1. Additional GPU targets: Should I add more GPU targets to `llvm.modf.ll`, keeping them exactly the same as `llvm/test/CodeGen/AMDGPU/llvm.frexp.ll`?
2. GlobalISel support: Currently only SelectionDAG is supported. Should GlobalISel support be added in this PR, or can it be a follow-up? 
3. Any extra tests should I include?

Thanks!

Fixes: #173021 

>From 56e715c4ebdd683259b847e77aac40a2fd99da7d Mon Sep 17 00:00:00 2001
From: Alex Wang <yesterda9 at gmail.com>
Date: Tue, 3 Feb 2026 02:37:49 -0800
Subject: [PATCH] [SelectionDAG] Add expansion for llvm.modf intrinsic

This expansion enables targets without a modf libcall to use the intrinsic instead of a library call. Targets with an available modf libcall will continue using the libcall.

Fixes: #173021
---
 llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp |  37 ++
 llvm/test/CodeGen/AMDGPU/llvm.modf.ll         | 322 ++++++++++++++++
 .../test/CodeGen/AMDGPU/modf-constant-fold.ll | 362 ++++++++++++++++++
 3 files changed, 721 insertions(+)
 create mode 100644 llvm/test/CodeGen/AMDGPU/llvm.modf.ll
 create mode 100644 llvm/test/CodeGen/AMDGPU/modf-constant-fold.ll

diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
index d9a2409b35e4c..aab0c86dcbf47 100644
--- a/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
@@ -184,6 +184,7 @@ class SelectionDAGLegalize {
   SDValue ExpandFNEG(SDNode *Node) const;
   SDValue expandLdexp(SDNode *Node) const;
   SDValue expandFrexp(SDNode *Node) const;
+  SDValue expandModf(SDNode *Node) const;
 
   SDValue ExpandLegalINT_TO_FP(SDNode *Node, SDValue &Chain);
   void PromoteLegalINT_TO_FP(SDNode *N, const SDLoc &dl,
@@ -2771,6 +2772,29 @@ SDValue SelectionDAGLegalize::expandFrexp(SDNode *Node) const {
   return DAG.getMergeValues({Result0, Result1}, dl);
 }
 
+SDValue SelectionDAGLegalize::expandModf(SDNode *Node) const {
+  SDLoc dl(Node);
+  SDValue Val = Node->getOperand(0);
+  EVT VT = Val.getValueType();
+
+  SDValue IntPart = DAG.getNode(ISD::FTRUNC, dl, VT, Val);
+  SDValue FracPart = DAG.getNode(ISD::FSUB, dl, VT, Val, IntPart);
+
+  SDValue Abs = DAG.getNode(ISD::FABS, dl, VT, Val);
+  SDValue Inf =
+      DAG.getConstantFP(APFloat::getInf(VT.getFltSemantics()), dl, VT);
+  EVT SetCCVT =
+      TLI.getSetCCResultType(DAG.getDataLayout(), *DAG.getContext(), VT);
+  SDValue IsInf = DAG.getSetCC(dl, SetCCVT, Abs, Inf, ISD::SETOEQ);
+  SDValue Zero = DAG.getConstantFP(0.0, dl, VT);
+  SDValue RawFrac = DAG.getNode(ISD::SELECT, dl, VT, IsInf, Zero, FracPart);
+
+  SDValue Result0 = DAG.getNode(ISD::FCOPYSIGN, dl, VT, RawFrac, Val);
+  SDValue Result1 = IntPart;
+
+  return DAG.getMergeValues({Result0, Result1}, dl);
+}
+
 /// This function is responsible for legalizing a
 /// INT_TO_FP operation of the specified operand when the target requests that
 /// we expand it.  At this point, we know that the result and operand types are
@@ -3920,6 +3944,19 @@ bool SelectionDAGLegalize::ExpandNode(SDNode *Node) {
     }
     break;
   }
+  case ISD::FMODF: {
+    RTLIB::Libcall LC = RTLIB::getMODF(Node->getValueType(0));
+    // Use the LibCall instead, it is very likely faster
+    // FIXME: Use separate LibCall action.
+    if (DAG.getLibcalls().getLibcallImpl(LC) != RTLIB::Unsupported)
+      break;
+
+    if (SDValue Expanded = expandModf(Node)) {
+      Results.push_back(Expanded);
+      Results.push_back(Expanded.getValue(1));
+    }
+    break;
+  }
   case ISD::FSINCOS: {
     if (isSinCosLibcallAvailable(Node, DAG.getLibcalls()))
       break;
diff --git a/llvm/test/CodeGen/AMDGPU/llvm.modf.ll b/llvm/test/CodeGen/AMDGPU/llvm.modf.ll
new file mode 100644
index 0000000000000..0deed99a44e7c
--- /dev/null
+++ b/llvm/test/CodeGen/AMDGPU/llvm.modf.ll
@@ -0,0 +1,322 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc -global-isel=0 -mtriple=amdgcn -mcpu=gfx900 < %s | FileCheck -check-prefixes=GFX9 %s
+
+; TODO: Add GlobalISel support
+
+declare { half, half } @llvm.modf.f16(half)
+declare { <2 x half>, <2 x half> } @llvm.modf.v2f16(<2 x half>)
+
+declare { float, float } @llvm.modf.f32(float)
+declare { <2 x float>, <2 x float> } @llvm.modf.v2f32(<2 x float>)
+
+declare { double, double } @llvm.modf.f64(double)
+declare { <2 x double>, <2 x double> } @llvm.modf.v2f64(<2 x double>)
+
+define { half, half } @test_modf_f16(half %x) {
+; GFX9-LABEL: test_modf_f16:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT:    s_movk_i32 s4, 0x7c00
+; GFX9-NEXT:    v_trunc_f16_e32 v1, v0
+; GFX9-NEXT:    v_sub_f16_e32 v2, v0, v1
+; GFX9-NEXT:    v_cmp_neq_f16_e64 vcc, |v0|, s4
+; GFX9-NEXT:    v_cndmask_b32_e32 v2, 0, v2, vcc
+; GFX9-NEXT:    s_movk_i32 s4, 0x7fff
+; GFX9-NEXT:    v_bfi_b32 v0, s4, v2, v0
+; GFX9-NEXT:    s_setpc_b64 s[30:31]
+  %result = call { half, half } @llvm.modf.f16(half %x)
+  ret { half, half } %result
+}
+
+define half @test_modf_f16_only_use_fract(half %x) {
+; GFX9-LABEL: test_modf_f16_only_use_fract:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT:    s_movk_i32 s4, 0x7c00
+; GFX9-NEXT:    v_trunc_f16_e32 v1, v0
+; GFX9-NEXT:    v_sub_f16_e32 v1, v0, v1
+; GFX9-NEXT:    v_cmp_neq_f16_e64 vcc, |v0|, s4
+; GFX9-NEXT:    v_cndmask_b32_e32 v1, 0, v1, vcc
+; GFX9-NEXT:    s_movk_i32 s4, 0x7fff
+; GFX9-NEXT:    v_bfi_b32 v0, s4, v1, v0
+; GFX9-NEXT:    s_setpc_b64 s[30:31]
+  %result = call { half, half } @llvm.modf.f16(half %x)
+  %result.0 = extractvalue { half, half } %result, 0
+  ret half %result.0
+}
+
+define half @test_modf_f16_only_use_integer(half %x) {
+; GFX9-LABEL: test_modf_f16_only_use_integer:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT:    v_trunc_f16_e32 v0, v0
+; GFX9-NEXT:    s_setpc_b64 s[30:31]
+  %result = call { half, half } @llvm.modf.f16(half %x)
+  %result.1 = extractvalue { half, half } %result, 1
+  ret half %result.1
+}
+
+define { <2 x half>, <2 x half> } @test_modf_v2f16(<2 x half> %x) {
+; GFX9-LABEL: test_modf_v2f16:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT:    s_movk_i32 s4, 0x7c00
+; GFX9-NEXT:    v_trunc_f16_e32 v1, v0
+; GFX9-NEXT:    v_sub_f16_e32 v2, v0, v1
+; GFX9-NEXT:    v_cmp_neq_f16_e64 vcc, |v0|, s4
+; GFX9-NEXT:    v_cndmask_b32_e32 v2, 0, v2, vcc
+; GFX9-NEXT:    s_movk_i32 s5, 0x7fff
+; GFX9-NEXT:    v_bfi_b32 v2, s5, v2, v0
+; GFX9-NEXT:    v_lshrrev_b32_e32 v0, 16, v0
+; GFX9-NEXT:    v_trunc_f16_e32 v3, v0
+; GFX9-NEXT:    v_sub_f16_e32 v4, v0, v3
+; GFX9-NEXT:    v_cmp_neq_f16_e64 vcc, |v0|, s4
+; GFX9-NEXT:    v_cndmask_b32_e32 v4, 0, v4, vcc
+; GFX9-NEXT:    v_bfi_b32 v0, s5, v4, v0
+; GFX9-NEXT:    v_pack_b32_f16 v0, v2, v0
+; GFX9-NEXT:    v_pack_b32_f16 v1, v1, v3
+; GFX9-NEXT:    s_setpc_b64 s[30:31]
+  %result = call { <2 x half>, <2 x half> } @llvm.modf.v2f16(<2 x half> %x)
+  ret { <2 x half>, <2 x half> } %result
+}
+
+define <2 x half> @test_modf_v2f16_only_use_fract(<2 x half> %x) {
+; GFX9-LABEL: test_modf_v2f16_only_use_fract:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT:    s_movk_i32 s4, 0x7c00
+; GFX9-NEXT:    v_trunc_f16_e32 v1, v0
+; GFX9-NEXT:    v_sub_f16_e32 v1, v0, v1
+; GFX9-NEXT:    v_cmp_neq_f16_e64 vcc, |v0|, s4
+; GFX9-NEXT:    v_cndmask_b32_e32 v1, 0, v1, vcc
+; GFX9-NEXT:    s_movk_i32 s5, 0x7fff
+; GFX9-NEXT:    v_bfi_b32 v1, s5, v1, v0
+; GFX9-NEXT:    v_lshrrev_b32_e32 v0, 16, v0
+; GFX9-NEXT:    v_trunc_f16_e32 v2, v0
+; GFX9-NEXT:    v_sub_f16_e32 v2, v0, v2
+; GFX9-NEXT:    v_cmp_neq_f16_e64 vcc, |v0|, s4
+; GFX9-NEXT:    v_cndmask_b32_e32 v2, 0, v2, vcc
+; GFX9-NEXT:    v_bfi_b32 v0, s5, v2, v0
+; GFX9-NEXT:    v_pack_b32_f16 v0, v1, v0
+; GFX9-NEXT:    s_setpc_b64 s[30:31]
+  %result = call { <2 x half>, <2 x half> } @llvm.modf.v2f16(<2 x half> %x)
+  %result.0 = extractvalue { <2 x half>, <2 x half> } %result, 0
+  ret <2 x half> %result.0
+}
+
+define <2 x half> @test_modf_v2f16_only_use_integer(<2 x half> %x) {
+; GFX9-LABEL: test_modf_v2f16_only_use_integer:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT:    v_trunc_f16_sdwa v1, v0 dst_sel:DWORD dst_unused:UNUSED_PAD src0_sel:WORD_1
+; GFX9-NEXT:    v_trunc_f16_e32 v0, v0
+; GFX9-NEXT:    v_pack_b32_f16 v0, v0, v1
+; GFX9-NEXT:    s_setpc_b64 s[30:31]
+  %result = call { <2 x half>, <2 x half> } @llvm.modf.v2f16(<2 x half> %x)
+  %result.1 = extractvalue { <2 x half>, <2 x half> } %result, 1
+  ret <2 x half> %result.1
+}
+
+define { float, float } @test_modf_f32(float %x) {
+; GFX9-LABEL: test_modf_f32:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT:    s_mov_b32 s4, 0x7f800000
+; GFX9-NEXT:    v_trunc_f32_e32 v1, v0
+; GFX9-NEXT:    v_sub_f32_e32 v2, v0, v1
+; GFX9-NEXT:    v_cmp_neq_f32_e64 vcc, |v0|, s4
+; GFX9-NEXT:    v_cndmask_b32_e32 v2, 0, v2, vcc
+; GFX9-NEXT:    s_brev_b32 s4, -2
+; GFX9-NEXT:    v_bfi_b32 v0, s4, v2, v0
+; GFX9-NEXT:    s_setpc_b64 s[30:31]
+  %result = call { float, float } @llvm.modf.f32(float %x)
+  ret { float, float } %result
+}
+
+define float @test_modf_f32_only_use_fract(float %x) {
+; GFX9-LABEL: test_modf_f32_only_use_fract:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT:    s_mov_b32 s4, 0x7f800000
+; GFX9-NEXT:    v_trunc_f32_e32 v1, v0
+; GFX9-NEXT:    v_sub_f32_e32 v1, v0, v1
+; GFX9-NEXT:    v_cmp_neq_f32_e64 vcc, |v0|, s4
+; GFX9-NEXT:    v_cndmask_b32_e32 v1, 0, v1, vcc
+; GFX9-NEXT:    s_brev_b32 s4, -2
+; GFX9-NEXT:    v_bfi_b32 v0, s4, v1, v0
+; GFX9-NEXT:    s_setpc_b64 s[30:31]
+  %result = call { float, float } @llvm.modf.f32(float %x)
+  %result.0 = extractvalue { float, float } %result, 0
+  ret float %result.0
+}
+
+define float @test_modf_f32_only_use_integer(float %x) {
+; GFX9-LABEL: test_modf_f32_only_use_integer:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT:    v_trunc_f32_e32 v0, v0
+; GFX9-NEXT:    s_setpc_b64 s[30:31]
+  %result = call { float, float } @llvm.modf.f32(float %x)
+  %result.1 = extractvalue { float, float } %result, 1
+  ret float %result.1
+}
+
+define { <2 x float>, <2 x float> } @test_modf_v2f32(<2 x float> %x) {
+; GFX9-LABEL: test_modf_v2f32:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT:    s_mov_b32 s4, 0x7f800000
+; GFX9-NEXT:    v_trunc_f32_e32 v2, v0
+; GFX9-NEXT:    v_sub_f32_e32 v3, v0, v2
+; GFX9-NEXT:    v_cmp_neq_f32_e64 vcc, |v0|, s4
+; GFX9-NEXT:    v_cndmask_b32_e32 v3, 0, v3, vcc
+; GFX9-NEXT:    s_brev_b32 s5, -2
+; GFX9-NEXT:    v_bfi_b32 v0, s5, v3, v0
+; GFX9-NEXT:    v_trunc_f32_e32 v3, v1
+; GFX9-NEXT:    v_sub_f32_e32 v4, v1, v3
+; GFX9-NEXT:    v_cmp_neq_f32_e64 vcc, |v1|, s4
+; GFX9-NEXT:    v_cndmask_b32_e32 v4, 0, v4, vcc
+; GFX9-NEXT:    v_bfi_b32 v1, s5, v4, v1
+; GFX9-NEXT:    s_setpc_b64 s[30:31]
+  %result = call { <2 x float>, <2 x float> } @llvm.modf.v2f32(<2 x float> %x)
+  ret { <2 x float>, <2 x float> } %result
+}
+
+define <2 x float> @test_modf_v2f32_only_use_fract(<2 x float> %x) {
+; GFX9-LABEL: test_modf_v2f32_only_use_fract:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT:    s_mov_b32 s4, 0x7f800000
+; GFX9-NEXT:    v_trunc_f32_e32 v2, v0
+; GFX9-NEXT:    v_sub_f32_e32 v2, v0, v2
+; GFX9-NEXT:    v_cmp_neq_f32_e64 vcc, |v0|, s4
+; GFX9-NEXT:    v_cndmask_b32_e32 v2, 0, v2, vcc
+; GFX9-NEXT:    s_brev_b32 s5, -2
+; GFX9-NEXT:    v_bfi_b32 v0, s5, v2, v0
+; GFX9-NEXT:    v_trunc_f32_e32 v2, v1
+; GFX9-NEXT:    v_sub_f32_e32 v2, v1, v2
+; GFX9-NEXT:    v_cmp_neq_f32_e64 vcc, |v1|, s4
+; GFX9-NEXT:    v_cndmask_b32_e32 v2, 0, v2, vcc
+; GFX9-NEXT:    v_bfi_b32 v1, s5, v2, v1
+; GFX9-NEXT:    s_setpc_b64 s[30:31]
+  %result = call { <2 x float>, <2 x float> } @llvm.modf.v2f32(<2 x float> %x)
+  %result.0 = extractvalue { <2 x float>, <2 x float> } %result, 0
+  ret <2 x float> %result.0
+}
+
+define <2 x float> @test_modf_v2f32_only_use_integer(<2 x float> %x) {
+; GFX9-LABEL: test_modf_v2f32_only_use_integer:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT:    v_trunc_f32_e32 v0, v0
+; GFX9-NEXT:    v_trunc_f32_e32 v1, v1
+; GFX9-NEXT:    s_setpc_b64 s[30:31]
+  %result = call { <2 x float>, <2 x float> } @llvm.modf.v2f32(<2 x float> %x)
+  %result.1 = extractvalue { <2 x float>, <2 x float> } %result, 1
+  ret <2 x float> %result.1
+}
+
+define { double, double } @test_modf_f64(double %x) {
+; GFX9-LABEL: test_modf_f64:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT:    v_trunc_f64_e32 v[2:3], v[0:1]
+; GFX9-NEXT:    s_movk_i32 s4, 0x204
+; GFX9-NEXT:    v_cmp_class_f64_e64 s[4:5], v[0:1], s4
+; GFX9-NEXT:    s_brev_b32 s6, -2
+; GFX9-NEXT:    v_add_f64 v[4:5], v[0:1], -v[2:3]
+; GFX9-NEXT:    v_cndmask_b32_e64 v0, v4, 0, s[4:5]
+; GFX9-NEXT:    v_cndmask_b32_e64 v4, v5, 0, s[4:5]
+; GFX9-NEXT:    v_bfi_b32 v1, s6, v4, v1
+; GFX9-NEXT:    s_setpc_b64 s[30:31]
+  %result = call { double, double } @llvm.modf.f64(double %x)
+  ret { double, double } %result
+}
+
+define double @test_modf_f64_only_use_fract(double %x) {
+; GFX9-LABEL: test_modf_f64_only_use_fract:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT:    v_trunc_f64_e32 v[2:3], v[0:1]
+; GFX9-NEXT:    s_movk_i32 s4, 0x204
+; GFX9-NEXT:    v_cmp_class_f64_e64 s[4:5], v[0:1], s4
+; GFX9-NEXT:    s_brev_b32 s6, -2
+; GFX9-NEXT:    v_add_f64 v[2:3], v[0:1], -v[2:3]
+; GFX9-NEXT:    v_cndmask_b32_e64 v0, v2, 0, s[4:5]
+; GFX9-NEXT:    v_cndmask_b32_e64 v2, v3, 0, s[4:5]
+; GFX9-NEXT:    v_bfi_b32 v1, s6, v2, v1
+; GFX9-NEXT:    s_setpc_b64 s[30:31]
+  %result = call { double, double } @llvm.modf.f64(double %x)
+  %result.0 = extractvalue { double, double } %result, 0
+  ret double %result.0
+}
+
+define double @test_modf_f64_only_use_integer(double %x) {
+; GFX9-LABEL: test_modf_f64_only_use_integer:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT:    v_trunc_f64_e32 v[0:1], v[0:1]
+; GFX9-NEXT:    s_setpc_b64 s[30:31]
+  %result = call { double, double } @llvm.modf.f64(double %x)
+  %result.1 = extractvalue { double, double } %result, 1
+  ret double %result.1
+}
+
+define { <2 x double>, <2 x double> } @test_modf_v2f64(<2 x double> %x) {
+; GFX9-LABEL: test_modf_v2f64:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT:    v_trunc_f64_e32 v[4:5], v[0:1]
+; GFX9-NEXT:    v_trunc_f64_e32 v[6:7], v[2:3]
+; GFX9-NEXT:    s_movk_i32 s6, 0x204
+; GFX9-NEXT:    v_cmp_class_f64_e64 s[4:5], v[0:1], s6
+; GFX9-NEXT:    v_cmp_class_f64_e64 s[6:7], v[2:3], s6
+; GFX9-NEXT:    s_brev_b32 s8, -2
+; GFX9-NEXT:    v_add_f64 v[8:9], v[0:1], -v[4:5]
+; GFX9-NEXT:    v_add_f64 v[10:11], v[2:3], -v[6:7]
+; GFX9-NEXT:    v_cndmask_b32_e64 v0, v8, 0, s[4:5]
+; GFX9-NEXT:    v_cndmask_b32_e64 v8, v9, 0, s[4:5]
+; GFX9-NEXT:    v_cndmask_b32_e64 v9, v11, 0, s[6:7]
+; GFX9-NEXT:    v_cndmask_b32_e64 v2, v10, 0, s[6:7]
+; GFX9-NEXT:    v_bfi_b32 v1, s8, v8, v1
+; GFX9-NEXT:    v_bfi_b32 v3, s8, v9, v3
+; GFX9-NEXT:    s_setpc_b64 s[30:31]
+  %result = call { <2 x double>, <2 x double> } @llvm.modf.v2f64(<2 x double> %x)
+  ret { <2 x double>, <2 x double> } %result
+}
+
+define <2 x double> @test_modf_v2f64_only_use_fract(<2 x double> %x) {
+; GFX9-LABEL: test_modf_v2f64_only_use_fract:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT:    v_trunc_f64_e32 v[4:5], v[0:1]
+; GFX9-NEXT:    v_trunc_f64_e32 v[6:7], v[2:3]
+; GFX9-NEXT:    s_movk_i32 s6, 0x204
+; GFX9-NEXT:    v_cmp_class_f64_e64 s[4:5], v[0:1], s6
+; GFX9-NEXT:    v_cmp_class_f64_e64 s[6:7], v[2:3], s6
+; GFX9-NEXT:    s_brev_b32 s8, -2
+; GFX9-NEXT:    v_add_f64 v[4:5], v[0:1], -v[4:5]
+; GFX9-NEXT:    v_add_f64 v[6:7], v[2:3], -v[6:7]
+; GFX9-NEXT:    v_cndmask_b32_e64 v0, v4, 0, s[4:5]
+; GFX9-NEXT:    v_cndmask_b32_e64 v4, v5, 0, s[4:5]
+; GFX9-NEXT:    v_cndmask_b32_e64 v5, v7, 0, s[6:7]
+; GFX9-NEXT:    v_cndmask_b32_e64 v2, v6, 0, s[6:7]
+; GFX9-NEXT:    v_bfi_b32 v1, s8, v4, v1
+; GFX9-NEXT:    v_bfi_b32 v3, s8, v5, v3
+; GFX9-NEXT:    s_setpc_b64 s[30:31]
+  %result = call { <2 x double>, <2 x double> } @llvm.modf.v2f64(<2 x double> %x)
+  %result.0 = extractvalue { <2 x double>, <2 x double> } %result, 0
+  ret <2 x double> %result.0
+}
+
+define <2 x double> @test_modf_v2f64_only_use_integer(<2 x double> %x) {
+; GFX9-LABEL: test_modf_v2f64_only_use_integer:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT:    v_trunc_f64_e32 v[0:1], v[0:1]
+; GFX9-NEXT:    v_trunc_f64_e32 v[2:3], v[2:3]
+; GFX9-NEXT:    s_setpc_b64 s[30:31]
+  %result = call { <2 x double>, <2 x double> } @llvm.modf.v2f64(<2 x double> %x)
+  %result.1 = extractvalue { <2 x double>, <2 x double> } %result, 1
+  ret <2 x double> %result.1
+}
diff --git a/llvm/test/CodeGen/AMDGPU/modf-constant-fold.ll b/llvm/test/CodeGen/AMDGPU/modf-constant-fold.ll
new file mode 100644
index 0000000000000..3d4edbe588a01
--- /dev/null
+++ b/llvm/test/CodeGen/AMDGPU/modf-constant-fold.ll
@@ -0,0 +1,362 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc -mtriple=amdgcn -mcpu=gfx900 < %s | FileCheck %s
+
+declare { float, float } @llvm.modf.f32(float)
+declare { <2 x float>, <2 x float> } @llvm.modf.v2f32(<2 x float>)
+declare { <4 x float>, <4 x float> } @llvm.modf.v4f32(<4 x float>)
+
+define { float, float } @modf_3_25() {
+; CHECK-LABEL: modf_3_25:
+; CHECK:       ; %bb.0:
+; CHECK-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; CHECK-NEXT:    v_mov_b32_e32 v0, 0x3e800000
+; CHECK-NEXT:    v_mov_b32_e32 v1, 0x40400000
+; CHECK-NEXT:    s_setpc_b64 s[30:31]
+  %ret = call { float, float } @llvm.modf.f32(float 0x400A000000000000)
+  ret { float, float } %ret
+}
+
+define { float, float } @modf_neg_3_25() {
+; CHECK-LABEL: modf_neg_3_25:
+; CHECK:       ; %bb.0:
+; CHECK-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; CHECK-NEXT:    v_mov_b32_e32 v0, 0xbe800000
+; CHECK-NEXT:    v_mov_b32_e32 v1, 0xc0400000
+; CHECK-NEXT:    s_setpc_b64 s[30:31]
+  %ret = call { float, float } @llvm.modf.f32(float 0xC00A000000000000)
+  ret { float, float } %ret
+}
+
+define { float, float } @modf_integer() {
+; CHECK-LABEL: modf_integer:
+; CHECK:       ; %bb.0:
+; CHECK-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; CHECK-NEXT:    v_bfrev_b32_e32 v0, 1
+; CHECK-NEXT:    v_mov_b32_e32 v1, 0xc2280000
+; CHECK-NEXT:    s_setpc_b64 s[30:31]
+  %ret = call { float, float } @llvm.modf.f32(float -42.0)
+  ret { float, float } %ret
+}
+
+define { float, float } @modf_fraction() {
+; CHECK-LABEL: modf_fraction:
+; CHECK:       ; %bb.0:
+; CHECK-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; CHECK-NEXT:    v_mov_b32_e32 v0, 0.5
+; CHECK-NEXT:    v_mov_b32_e32 v1, 0
+; CHECK-NEXT:    s_setpc_b64 s[30:31]
+  %ret = call { float, float } @llvm.modf.f32(float 0.5)
+  ret { float, float } %ret
+}
+
+define { float, float } @modf_zero() {
+; CHECK-LABEL: modf_zero:
+; CHECK:       ; %bb.0:
+; CHECK-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; CHECK-NEXT:    v_mov_b32_e32 v0, 0
+; CHECK-NEXT:    v_mov_b32_e32 v1, 0
+; CHECK-NEXT:    s_setpc_b64 s[30:31]
+  %ret = call { float, float } @llvm.modf.f32(float 0.0)
+  ret { float, float } %ret
+}
+
+define { float, float } @modf_negzero() {
+; CHECK-LABEL: modf_negzero:
+; CHECK:       ; %bb.0:
+; CHECK-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; CHECK-NEXT:    v_bfrev_b32_e32 v0, 1
+; CHECK-NEXT:    v_bfrev_b32_e32 v1, 1
+; CHECK-NEXT:    s_setpc_b64 s[30:31]
+  %ret = call { float, float } @llvm.modf.f32(float -0.0)
+  ret { float, float } %ret
+}
+
+define { float, float } @modf_inf() {
+; CHECK-LABEL: modf_inf:
+; CHECK:       ; %bb.0:
+; CHECK-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; CHECK-NEXT:    v_mov_b32_e32 v0, 0
+; CHECK-NEXT:    v_mov_b32_e32 v1, 0x7f800000
+; CHECK-NEXT:    s_setpc_b64 s[30:31]
+  %ret = call { float, float } @llvm.modf.f32(float 0x7FF0000000000000)
+  ret { float, float } %ret
+}
+
+define { float, float } @modf_neginf() {
+; CHECK-LABEL: modf_neginf:
+; CHECK:       ; %bb.0:
+; CHECK-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; CHECK-NEXT:    v_bfrev_b32_e32 v0, 1
+; CHECK-NEXT:    v_mov_b32_e32 v1, 0xff800000
+; CHECK-NEXT:    s_setpc_b64 s[30:31]
+  %ret = call { float, float } @llvm.modf.f32(float 0xFFF0000000000000)
+  ret { float, float } %ret
+}
+
+define { float, float } @modf_qnan() {
+; CHECK-LABEL: modf_qnan:
+; CHECK:       ; %bb.0:
+; CHECK-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; CHECK-NEXT:    v_mov_b32_e32 v0, 0x7fc00000
+; CHECK-NEXT:    v_mov_b32_e32 v1, 0x7fc00000
+; CHECK-NEXT:    s_setpc_b64 s[30:31]
+  %ret = call { float, float } @llvm.modf.f32(float 0x7FF8000000000000)
+  ret { float, float } %ret
+}
+
+define { float, float } @modf_snan() {
+; CHECK-LABEL: modf_snan:
+; CHECK:       ; %bb.0:
+; CHECK-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; CHECK-NEXT:    v_trunc_f32_e32 v1, 0x7f800001
+; CHECK-NEXT:    v_sub_f32_e32 v0, 0x7f800001, v1
+; CHECK-NEXT:    v_and_b32_e32 v0, 0x7fffffff, v0
+; CHECK-NEXT:    s_setpc_b64 s[30:31]
+  %ret = call { float, float } @llvm.modf.f32(float bitcast (i32 2139095041 to float))
+  ret { float, float } %ret
+}
+
+define { float, float } @modf_pos_denorm() {
+; CHECK-LABEL: modf_pos_denorm:
+; CHECK:       ; %bb.0:
+; CHECK-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; CHECK-NEXT:    v_mov_b32_e32 v0, 0x7fffff
+; CHECK-NEXT:    v_mov_b32_e32 v1, 0
+; CHECK-NEXT:    s_setpc_b64 s[30:31]
+  %ret = call { float, float } @llvm.modf.f32(float bitcast (i32 8388607 to float))
+  ret { float, float } %ret
+}
+
+define { float, float } @modf_neg_denorm() {
+; CHECK-LABEL: modf_neg_denorm:
+; CHECK:       ; %bb.0:
+; CHECK-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; CHECK-NEXT:    v_mov_b32_e32 v0, 0x807fffff
+; CHECK-NEXT:    v_bfrev_b32_e32 v1, 1
+; CHECK-NEXT:    s_setpc_b64 s[30:31]
+  %ret = call { float, float } @llvm.modf.f32(float bitcast (i32 -2139095041 to float))
+  ret { float, float } %ret
+}
+
+define { float, float } @modf_posion() {
+; CHECK-LABEL: modf_posion:
+; CHECK:       ; %bb.0:
+; CHECK-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; CHECK-NEXT:    s_setpc_b64 s[30:31]
+  %ret = call { float, float } @llvm.modf.f32(float poison)
+  ret { float, float } %ret
+}
+
+define { <2 x float>, <2 x float> } @modf_posion_vector() {
+; CHECK-LABEL: modf_posion_vector:
+; CHECK:       ; %bb.0:
+; CHECK-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; CHECK-NEXT:    s_setpc_b64 s[30:31]
+  %ret = call { <2 x float>, <2 x float> } @llvm.modf.v2f32(<2 x float> poison)
+  ret { <2 x float>, <2 x float> } %ret
+}
+
+define { float, float } @modf_undef() {
+; CHECK-LABEL: modf_undef:
+; CHECK:       ; %bb.0:
+; CHECK-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; CHECK-NEXT:    s_and_b32 s4, 0x80000000, s4
+; CHECK-NEXT:    v_trunc_f32_e32 v1, s4
+; CHECK-NEXT:    v_mov_b32_e32 v0, s4
+; CHECK-NEXT:    s_setpc_b64 s[30:31]
+  %ret = call { float, float } @llvm.modf.f32(float undef)
+  ret { float, float } %ret
+}
+
+define { <2 x float>, <2 x float> } @modf_undef_vector() {
+; CHECK-LABEL: modf_undef_vector:
+; CHECK:       ; %bb.0:
+; CHECK-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; CHECK-NEXT:    s_and_b32 s4, 0x80000000, s4
+; CHECK-NEXT:    v_trunc_f32_e32 v2, s4
+; CHECK-NEXT:    v_mov_b32_e32 v0, s4
+; CHECK-NEXT:    v_mov_b32_e32 v1, s4
+; CHECK-NEXT:    v_mov_b32_e32 v3, v2
+; CHECK-NEXT:    s_setpc_b64 s[30:31]
+  %ret = call { <2 x float>, <2 x float> } @llvm.modf.v2f32(<2 x float> undef)
+  ret { <2 x float>, <2 x float> } %ret
+}
+
+define { <2 x float>, <2 x float> } @modf_zero_vector() {
+; CHECK-LABEL: modf_zero_vector:
+; CHECK:       ; %bb.0:
+; CHECK-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; CHECK-NEXT:    v_mov_b32_e32 v0, 0
+; CHECK-NEXT:    v_mov_b32_e32 v1, 0
+; CHECK-NEXT:    v_mov_b32_e32 v2, 0
+; CHECK-NEXT:    v_mov_b32_e32 v3, 0
+; CHECK-NEXT:    s_setpc_b64 s[30:31]
+  %ret = call { <2 x float>, <2 x float> } @llvm.modf.v2f32(<2 x float> zeroinitializer)
+  ret { <2 x float>, <2 x float> } %ret
+}
+
+define { <2 x float>, <2 x float> } @modf_zero_negzero_vector() {
+; CHECK-LABEL: modf_zero_negzero_vector:
+; CHECK:       ; %bb.0:
+; CHECK-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; CHECK-NEXT:    v_mov_b32_e32 v0, 0
+; CHECK-NEXT:    v_bfrev_b32_e32 v1, 1
+; CHECK-NEXT:    v_mov_b32_e32 v2, 0
+; CHECK-NEXT:    v_bfrev_b32_e32 v3, 1
+; CHECK-NEXT:    s_setpc_b64 s[30:31]
+  %ret = call { <2 x float>, <2 x float> } @llvm.modf.v2f32(<2 x float> <float 0.0, float -0.0>)
+  ret { <2 x float>, <2 x float> } %ret
+}
+
+define { float, float } @modf_modf(float %x) {
+; CHECK-LABEL: modf_modf:
+; CHECK:       ; %bb.0:
+; CHECK-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; CHECK-NEXT:    s_mov_b32 s4, 0x7f800000
+; CHECK-NEXT:    v_trunc_f32_e32 v1, v0
+; CHECK-NEXT:    v_sub_f32_e32 v1, v0, v1
+; CHECK-NEXT:    v_cmp_neq_f32_e64 vcc, |v0|, s4
+; CHECK-NEXT:    v_cndmask_b32_e32 v1, 0, v1, vcc
+; CHECK-NEXT:    s_brev_b32 s5, -2
+; CHECK-NEXT:    v_bfi_b32 v0, s5, v1, v0
+; CHECK-NEXT:    v_trunc_f32_e32 v1, v0
+; CHECK-NEXT:    v_sub_f32_e32 v2, v0, v1
+; CHECK-NEXT:    v_cmp_neq_f32_e64 vcc, |v0|, s4
+; CHECK-NEXT:    v_cndmask_b32_e32 v2, 0, v2, vcc
+; CHECK-NEXT:    v_bfi_b32 v0, s5, v2, v0
+; CHECK-NEXT:    s_setpc_b64 s[30:31]
+  %modf0 = call { float, float } @llvm.modf.f32(float %x)
+  %modf0.0 = extractvalue { float, float } %modf0, 0
+  %modf1 = call { float, float } @llvm.modf.f32(float %modf0.0)
+  ret { float, float } %modf1
+}
+
+define { <2 x float>, <2 x float> } @modf_modf_vector(<2 x float> %x) {
+; CHECK-LABEL: modf_modf_vector:
+; CHECK:       ; %bb.0:
+; CHECK-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; CHECK-NEXT:    s_mov_b32 s4, 0x7f800000
+; CHECK-NEXT:    v_trunc_f32_e32 v2, v1
+; CHECK-NEXT:    v_sub_f32_e32 v2, v1, v2
+; CHECK-NEXT:    v_cmp_neq_f32_e64 vcc, |v1|, s4
+; CHECK-NEXT:    v_cndmask_b32_e32 v2, 0, v2, vcc
+; CHECK-NEXT:    s_brev_b32 s5, -2
+; CHECK-NEXT:    v_bfi_b32 v1, s5, v2, v1
+; CHECK-NEXT:    v_trunc_f32_e32 v2, v0
+; CHECK-NEXT:    v_sub_f32_e32 v2, v0, v2
+; CHECK-NEXT:    v_cmp_neq_f32_e64 vcc, |v0|, s4
+; CHECK-NEXT:    v_cndmask_b32_e32 v2, 0, v2, vcc
+; CHECK-NEXT:    v_bfi_b32 v0, s5, v2, v0
+; CHECK-NEXT:    v_trunc_f32_e32 v2, v0
+; CHECK-NEXT:    v_sub_f32_e32 v3, v0, v2
+; CHECK-NEXT:    v_cmp_neq_f32_e64 vcc, |v0|, s4
+; CHECK-NEXT:    v_cndmask_b32_e32 v3, 0, v3, vcc
+; CHECK-NEXT:    v_bfi_b32 v0, s5, v3, v0
+; CHECK-NEXT:    v_trunc_f32_e32 v3, v1
+; CHECK-NEXT:    v_sub_f32_e32 v4, v1, v3
+; CHECK-NEXT:    v_cmp_neq_f32_e64 vcc, |v1|, s4
+; CHECK-NEXT:    v_cndmask_b32_e32 v4, 0, v4, vcc
+; CHECK-NEXT:    v_bfi_b32 v1, s5, v4, v1
+; CHECK-NEXT:    s_setpc_b64 s[30:31]
+  %modf0 = call { <2 x float>, <2 x float> } @llvm.modf.v2f32(<2 x float> %x)
+  %modf0.0 = extractvalue { <2 x float>, <2 x float> } %modf0, 0
+  %modf1 = call { <2 x float>, <2 x float> } @llvm.modf.v2f32(<2 x float> %modf0.0)
+  ret { <2 x float>, <2 x float> } %modf1
+}
+
+define { float, float } @modf_modf_const(float %x) {
+; CHECK-LABEL: modf_modf_const:
+; CHECK:       ; %bb.0:
+; CHECK-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; CHECK-NEXT:    v_mov_b32_e32 v0, 0x3e800000
+; CHECK-NEXT:    v_mov_b32_e32 v1, 0
+; CHECK-NEXT:    s_setpc_b64 s[30:31]
+  %modf0 = call { float, float } @llvm.modf.f32(float 0x400A000000000000)
+  %modf0.0 = extractvalue { float, float } %modf0, 0
+  %modf1 = call { float, float } @llvm.modf.f32(float %modf0.0)
+  ret { float, float } %modf1
+}
+
+define { <4 x float>, <4 x float> } @modf_nonsplat_vector() {
+; CHECK-LABEL: modf_nonsplat_vector:
+; CHECK:       ; %bb.0:
+; CHECK-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; CHECK-NEXT:    s_and_b32 s4, 0x80000000, s4
+; CHECK-NEXT:    v_trunc_f32_e32 v6, s4
+; CHECK-NEXT:    v_mov_b32_e32 v0, 0x3e800000
+; CHECK-NEXT:    v_bfrev_b32_e32 v1, 1
+; CHECK-NEXT:    v_mov_b32_e32 v2, s4
+; CHECK-NEXT:    v_mov_b32_e32 v3, 0
+; CHECK-NEXT:    v_mov_b32_e32 v4, 0x40400000
+; CHECK-NEXT:    v_mov_b32_e32 v5, 0xc2000000
+; CHECK-NEXT:    v_mov_b32_e32 v7, 0x4479c000
+; CHECK-NEXT:    s_setpc_b64 s[30:31]
+  %ret = call { <4 x float>, <4 x float> } @llvm.modf.v4f32(<4 x float> <float 0x400A000000000000, float -32.0, float undef, float 999.0>)
+  ret { <4 x float>, <4 x float> } %ret
+}
+
+define { <2 x float>, <2 x float> } @modf_splat_3_25() {
+; CHECK-LABEL: modf_splat_3_25:
+; CHECK:       ; %bb.0:
+; CHECK-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; CHECK-NEXT:    v_mov_b32_e32 v0, 0x3e800000
+; CHECK-NEXT:    v_mov_b32_e32 v1, 0x3e800000
+; CHECK-NEXT:    v_mov_b32_e32 v2, 0x40400000
+; CHECK-NEXT:    v_mov_b32_e32 v3, 0x40400000
+; CHECK-NEXT:    s_setpc_b64 s[30:31]
+  %ret = call { <2 x float>, <2 x float> } @llvm.modf.v2f32(<2 x float> <float 0x400A000000000000, float 0x400A000000000000>)
+  ret { <2 x float>, <2 x float> } %ret
+}
+
+define { <2 x float>, <2 x float> } @modf_splat_qnan() {
+; CHECK-LABEL: modf_splat_qnan:
+; CHECK:       ; %bb.0:
+; CHECK-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; CHECK-NEXT:    v_mov_b32_e32 v0, 0x7fc00000
+; CHECK-NEXT:    v_mov_b32_e32 v1, 0x7fc00000
+; CHECK-NEXT:    v_mov_b32_e32 v2, 0x7fc00000
+; CHECK-NEXT:    v_mov_b32_e32 v3, 0x7fc00000
+; CHECK-NEXT:    s_setpc_b64 s[30:31]
+  %ret = call { <2 x float>, <2 x float> } @llvm.modf.v2f32(<2 x float> <float 0x7FF8000000000000, float 0x7FF8000000000000>)
+  ret { <2 x float>, <2 x float> } %ret
+}
+
+define { <2 x float>, <2 x float> } @modf_splat_inf() {
+; CHECK-LABEL: modf_splat_inf:
+; CHECK:       ; %bb.0:
+; CHECK-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; CHECK-NEXT:    v_mov_b32_e32 v0, 0
+; CHECK-NEXT:    v_mov_b32_e32 v1, 0
+; CHECK-NEXT:    v_mov_b32_e32 v2, 0x7f800000
+; CHECK-NEXT:    v_mov_b32_e32 v3, 0x7f800000
+; CHECK-NEXT:    s_setpc_b64 s[30:31]
+  %ret = call { <2 x float>, <2 x float> } @llvm.modf.v2f32(<2 x float> <float 0x7FF0000000000000, float 0x7FF0000000000000>)
+  ret { <2 x float>, <2 x float> } %ret
+}
+
+define { <2 x float>, <2 x float> } @modf_splat_neginf() {
+; CHECK-LABEL: modf_splat_neginf:
+; CHECK:       ; %bb.0:
+; CHECK-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; CHECK-NEXT:    v_bfrev_b32_e32 v0, 1
+; CHECK-NEXT:    v_bfrev_b32_e32 v1, 1
+; CHECK-NEXT:    v_mov_b32_e32 v2, 0xff800000
+; CHECK-NEXT:    v_mov_b32_e32 v3, 0xff800000
+; CHECK-NEXT:    s_setpc_b64 s[30:31]
+  %ret = call { <2 x float>, <2 x float> } @llvm.modf.v2f32(<2 x float> <float 0xFFF0000000000000, float 0xFFF0000000000000>)
+  ret { <2 x float>, <2 x float> } %ret
+}
+
+define { <2 x float>, <2 x float> } @modf_splat_undef_inf() {
+; CHECK-LABEL: modf_splat_undef_inf:
+; CHECK:       ; %bb.0:
+; CHECK-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; CHECK-NEXT:    s_and_b32 s4, 0x80000000, s4
+; CHECK-NEXT:    v_trunc_f32_e32 v2, s4
+; CHECK-NEXT:    v_mov_b32_e32 v0, s4
+; CHECK-NEXT:    v_mov_b32_e32 v1, 0
+; CHECK-NEXT:    v_mov_b32_e32 v3, 0x7f800000
+; CHECK-NEXT:    s_setpc_b64 s[30:31]
+  %ret = call { <2 x float>, <2 x float> } @llvm.modf.v2f32(<2 x float> <float undef, float 0x7FF0000000000000>)
+  ret { <2 x float>, <2 x float> } %ret
+}



More information about the llvm-commits mailing list