[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