[llvm] [LoongArch] Combine FP_TO_UINT/FP_TO_SINT with [X]VFTINTRZ instruction (PR #201569)

via llvm-commits llvm-commits at lists.llvm.org
Thu Jun 4 05:31:04 PDT 2026


https://github.com/lrzlin created https://github.com/llvm/llvm-project/pull/201569

Combine double convert to signed 32-bit integer with `[X]VFTINTRZ_W_D` instructions, avoid doing so with LASX double to uint32 because we already have the corresponding tablegen pattern.

Rely on: https://github.com/llvm/llvm-project/pull/201548

>From 815acdab0b61fa845dc01ae4794ae02d8e466c16 Mon Sep 17 00:00:00 2001
From: Lin Runze <linrunze at loongson.cn>
Date: Thu, 4 Jun 2026 19:59:22 +0800
Subject: [PATCH 1/2] [LoongArch][NFC] Add double to signed/unsigned i32 tests
 for LSX and LASX

---
 .../LoongArch/lasx/ir-instruction/fptosi.ll   |  20 ++
 .../LoongArch/lasx/ir-instruction/fptoui.ll   | 123 +++++++++---
 .../LoongArch/lsx/ir-instruction/fptosi.ll    | 125 ++++++++++--
 .../LoongArch/lsx/ir-instruction/fptoui.ll    | 189 ++++++++++++++++--
 4 files changed, 400 insertions(+), 57 deletions(-)

diff --git a/llvm/test/CodeGen/LoongArch/lasx/ir-instruction/fptosi.ll b/llvm/test/CodeGen/LoongArch/lasx/ir-instruction/fptosi.ll
index 5b63ef3e53a4c..861052b0ffec1 100644
--- a/llvm/test/CodeGen/LoongArch/lasx/ir-instruction/fptosi.ll
+++ b/llvm/test/CodeGen/LoongArch/lasx/ir-instruction/fptosi.ll
@@ -43,6 +43,26 @@ define void @fptosi_v4f64_v4i32(ptr %res, ptr %in){
   ret void
 }
 
+define void @fptosi_v8f64_v8i32(ptr %res, ptr %in){
+; CHECK-LABEL: fptosi_v8f64_v8i32:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    xvld $xr0, $a1, 32
+; CHECK-NEXT:    xvld $xr1, $a1, 0
+; CHECK-NEXT:    xvftintrz.l.d $xr0, $xr0
+; CHECK-NEXT:    xvpermi.d $xr2, $xr0, 238
+; CHECK-NEXT:    xvpickev.w $xr0, $xr2, $xr0
+; CHECK-NEXT:    xvftintrz.l.d $xr1, $xr1
+; CHECK-NEXT:    xvpermi.d $xr2, $xr1, 238
+; CHECK-NEXT:    xvpickev.w $xr1, $xr2, $xr1
+; CHECK-NEXT:    xvpermi.q $xr1, $xr0, 2
+; CHECK-NEXT:    xvst $xr1, $a0, 0
+; CHECK-NEXT:    ret
+  %v0 = load <8 x double>, ptr %in
+  %v1 = fptosi <8 x double> %v0 to <8 x i32>
+  store <8 x i32> %v1, ptr %res
+  ret void
+}
+
 define void @fptosi_v4f32_v4i64(ptr %res, ptr %in){
 ; CHECK-LABEL: fptosi_v4f32_v4i64:
 ; CHECK:       # %bb.0:
diff --git a/llvm/test/CodeGen/LoongArch/lasx/ir-instruction/fptoui.ll b/llvm/test/CodeGen/LoongArch/lasx/ir-instruction/fptoui.ll
index 4c699a0721bff..0f60d782c0fc5 100644
--- a/llvm/test/CodeGen/LoongArch/lasx/ir-instruction/fptoui.ll
+++ b/llvm/test/CodeGen/LoongArch/lasx/ir-instruction/fptoui.ll
@@ -1,14 +1,21 @@
 ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 3
-; RUN: llc --mtriple=loongarch32 --mattr=+32s,+lasx < %s | FileCheck %s
-; RUN: llc --mtriple=loongarch64 --mattr=+lasx < %s | FileCheck %s
+; RUN: llc --mtriple=loongarch32 --mattr=+32s,+lasx < %s | FileCheck %s --check-prefix=LA32
+; RUN: llc --mtriple=loongarch64 --mattr=+lasx < %s | FileCheck %s --check-prefix=LA64
 
 define void @fptoui_v8f32_v8i32(ptr %res, ptr %in){
-; CHECK-LABEL: fptoui_v8f32_v8i32:
-; CHECK:       # %bb.0:
-; CHECK-NEXT:    xvld $xr0, $a1, 0
-; CHECK-NEXT:    xvftintrz.wu.s $xr0, $xr0
-; CHECK-NEXT:    xvst $xr0, $a0, 0
-; CHECK-NEXT:    ret
+; LA32-LABEL: fptoui_v8f32_v8i32:
+; LA32:       # %bb.0:
+; LA32-NEXT:    xvld $xr0, $a1, 0
+; LA32-NEXT:    xvftintrz.wu.s $xr0, $xr0
+; LA32-NEXT:    xvst $xr0, $a0, 0
+; LA32-NEXT:    ret
+;
+; LA64-LABEL: fptoui_v8f32_v8i32:
+; LA64:       # %bb.0:
+; LA64-NEXT:    xvld $xr0, $a1, 0
+; LA64-NEXT:    xvftintrz.wu.s $xr0, $xr0
+; LA64-NEXT:    xvst $xr0, $a0, 0
+; LA64-NEXT:    ret
   %v0 = load <8 x float>, ptr %in
   %v1 = fptoui <8 x float> %v0 to <8 x i32>
   store <8 x i32> %v1, ptr %res
@@ -16,12 +23,19 @@ define void @fptoui_v8f32_v8i32(ptr %res, ptr %in){
 }
 
 define void @fptoui_v4f64_v4i64(ptr %res, ptr %in){
-; CHECK-LABEL: fptoui_v4f64_v4i64:
-; CHECK:       # %bb.0:
-; CHECK-NEXT:    xvld $xr0, $a1, 0
-; CHECK-NEXT:    xvftintrz.lu.d $xr0, $xr0
-; CHECK-NEXT:    xvst $xr0, $a0, 0
-; CHECK-NEXT:    ret
+; LA32-LABEL: fptoui_v4f64_v4i64:
+; LA32:       # %bb.0:
+; LA32-NEXT:    xvld $xr0, $a1, 0
+; LA32-NEXT:    xvftintrz.lu.d $xr0, $xr0
+; LA32-NEXT:    xvst $xr0, $a0, 0
+; LA32-NEXT:    ret
+;
+; LA64-LABEL: fptoui_v4f64_v4i64:
+; LA64:       # %bb.0:
+; LA64-NEXT:    xvld $xr0, $a1, 0
+; LA64-NEXT:    xvftintrz.lu.d $xr0, $xr0
+; LA64-NEXT:    xvst $xr0, $a0, 0
+; LA64-NEXT:    ret
   %v0 = load <4 x double>, ptr %in
   %v1 = fptoui <4 x double> %v0 to <4 x i64>
   store <4 x i64> %v1, ptr %res
@@ -29,28 +43,79 @@ define void @fptoui_v4f64_v4i64(ptr %res, ptr %in){
 }
 
 define void @fptoui_v4f64_v4i32(ptr %res, ptr %in){
-; CHECK-LABEL: fptoui_v4f64_v4i32:
-; CHECK:       # %bb.0:
-; CHECK-NEXT:    xvld $xr0, $a1, 0
-; CHECK-NEXT:    xvftintrz.lu.d $xr0, $xr0
-; CHECK-NEXT:    xvpermi.d $xr1, $xr0, 238
-; CHECK-NEXT:    xvpickev.w $xr0, $xr1, $xr0
-; CHECK-NEXT:    vst $vr0, $a0, 0
-; CHECK-NEXT:    ret
+; LA32-LABEL: fptoui_v4f64_v4i32:
+; LA32:       # %bb.0:
+; LA32-NEXT:    xvld $xr0, $a1, 0
+; LA32-NEXT:    xvftintrz.lu.d $xr0, $xr0
+; LA32-NEXT:    xvpermi.d $xr1, $xr0, 238
+; LA32-NEXT:    xvpickev.w $xr0, $xr1, $xr0
+; LA32-NEXT:    vst $vr0, $a0, 0
+; LA32-NEXT:    ret
+;
+; LA64-LABEL: fptoui_v4f64_v4i32:
+; LA64:       # %bb.0:
+; LA64-NEXT:    xvld $xr0, $a1, 0
+; LA64-NEXT:    xvftintrz.lu.d $xr0, $xr0
+; LA64-NEXT:    xvpermi.d $xr1, $xr0, 238
+; LA64-NEXT:    xvpickev.w $xr0, $xr1, $xr0
+; LA64-NEXT:    vst $vr0, $a0, 0
+; LA64-NEXT:    ret
   %v0 = load <4 x double>, ptr %in
   %v1 = fptoui <4 x double> %v0 to <4 x i32>
   store <4 x i32> %v1, ptr %res
   ret void
 }
 
+define void @fptoui_v8f64_v8i32(ptr %res, ptr %in){
+; LA32-LABEL: fptoui_v8f64_v8i32:
+; LA32:       # %bb.0:
+; LA32-NEXT:    xvld $xr0, $a1, 32
+; LA32-NEXT:    xvld $xr1, $a1, 0
+; LA32-NEXT:    xvftintrz.lu.d $xr0, $xr0
+; LA32-NEXT:    xvpermi.d $xr2, $xr0, 238
+; LA32-NEXT:    xvpickev.w $xr0, $xr2, $xr0
+; LA32-NEXT:    xvftintrz.lu.d $xr1, $xr1
+; LA32-NEXT:    xvpermi.d $xr2, $xr1, 238
+; LA32-NEXT:    xvpickev.w $xr1, $xr2, $xr1
+; LA32-NEXT:    xvpermi.q $xr1, $xr0, 2
+; LA32-NEXT:    xvst $xr1, $a0, 0
+; LA32-NEXT:    ret
+;
+; LA64-LABEL: fptoui_v8f64_v8i32:
+; LA64:       # %bb.0:
+; LA64-NEXT:    xvld $xr0, $a1, 32
+; LA64-NEXT:    xvld $xr1, $a1, 0
+; LA64-NEXT:    xvftintrz.lu.d $xr0, $xr0
+; LA64-NEXT:    xvpermi.d $xr2, $xr0, 238
+; LA64-NEXT:    xvpickev.w $xr0, $xr2, $xr0
+; LA64-NEXT:    xvftintrz.lu.d $xr1, $xr1
+; LA64-NEXT:    xvpermi.d $xr2, $xr1, 238
+; LA64-NEXT:    xvpickev.w $xr1, $xr2, $xr1
+; LA64-NEXT:    xvpermi.q $xr1, $xr0, 2
+; LA64-NEXT:    xvst $xr1, $a0, 0
+; LA64-NEXT:    ret
+  %v0 = load <8 x double>, ptr %in
+  %v1 = fptoui <8 x double> %v0 to <8 x i32>
+  store <8 x i32> %v1, ptr %res
+  ret void
+}
+
 define void @fptoui_v4f32_v4i64(ptr %res, ptr %in){
-; CHECK-LABEL: fptoui_v4f32_v4i64:
-; CHECK:       # %bb.0:
-; CHECK-NEXT:    vld $vr0, $a1, 0
-; CHECK-NEXT:    vftintrz.wu.s $vr0, $vr0
-; CHECK-NEXT:    vext2xv.du.wu $xr0, $xr0
-; CHECK-NEXT:    xvst $xr0, $a0, 0
-; CHECK-NEXT:    ret
+; LA32-LABEL: fptoui_v4f32_v4i64:
+; LA32:       # %bb.0:
+; LA32-NEXT:    vld $vr0, $a1, 0
+; LA32-NEXT:    vftintrz.wu.s $vr0, $vr0
+; LA32-NEXT:    vext2xv.du.wu $xr0, $xr0
+; LA32-NEXT:    xvst $xr0, $a0, 0
+; LA32-NEXT:    ret
+;
+; LA64-LABEL: fptoui_v4f32_v4i64:
+; LA64:       # %bb.0:
+; LA64-NEXT:    vld $vr0, $a1, 0
+; LA64-NEXT:    vftintrz.wu.s $vr0, $vr0
+; LA64-NEXT:    vext2xv.du.wu $xr0, $xr0
+; LA64-NEXT:    xvst $xr0, $a0, 0
+; LA64-NEXT:    ret
   %v0 = load <4 x float>, ptr %in
   %v1 = fptoui <4 x float> %v0 to <4 x i64>
   store <4 x i64> %v1, ptr %res
diff --git a/llvm/test/CodeGen/LoongArch/lsx/ir-instruction/fptosi.ll b/llvm/test/CodeGen/LoongArch/lsx/ir-instruction/fptosi.ll
index 7ea6d7431670e..76bc8225a4ae8 100644
--- a/llvm/test/CodeGen/LoongArch/lsx/ir-instruction/fptosi.ll
+++ b/llvm/test/CodeGen/LoongArch/lsx/ir-instruction/fptosi.ll
@@ -1,14 +1,21 @@
 ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 3
-; RUN: llc --mtriple=loongarch32 --mattr=+32s,+lsx < %s | FileCheck %s
-; RUN: llc --mtriple=loongarch64 --mattr=+lsx < %s | FileCheck %s
+; RUN: llc --mtriple=loongarch32 --mattr=+32s,+lsx < %s | FileCheck %s --check-prefix=LA32
+; RUN: llc --mtriple=loongarch64 --mattr=+lsx < %s | FileCheck %s --check-prefix=LA64
 
 define void @fptosi_v4f32_v4i32(ptr %res, ptr %in){
-; CHECK-LABEL: fptosi_v4f32_v4i32:
-; CHECK:       # %bb.0:
-; CHECK-NEXT:    vld $vr0, $a1, 0
-; CHECK-NEXT:    vftintrz.w.s $vr0, $vr0
-; CHECK-NEXT:    vst $vr0, $a0, 0
-; CHECK-NEXT:    ret
+; LA32-LABEL: fptosi_v4f32_v4i32:
+; LA32:       # %bb.0:
+; LA32-NEXT:    vld $vr0, $a1, 0
+; LA32-NEXT:    vftintrz.w.s $vr0, $vr0
+; LA32-NEXT:    vst $vr0, $a0, 0
+; LA32-NEXT:    ret
+;
+; LA64-LABEL: fptosi_v4f32_v4i32:
+; LA64:       # %bb.0:
+; LA64-NEXT:    vld $vr0, $a1, 0
+; LA64-NEXT:    vftintrz.w.s $vr0, $vr0
+; LA64-NEXT:    vst $vr0, $a0, 0
+; LA64-NEXT:    ret
   %v0 = load <4 x float>, ptr %in
   %v1 = fptosi <4 x float> %v0 to <4 x i32>
   store <4 x i32> %v1, ptr %res
@@ -16,14 +23,104 @@ define void @fptosi_v4f32_v4i32(ptr %res, ptr %in){
 }
 
 define void @fptosi_v2f64_v2i64(ptr %res, ptr %in){
-; CHECK-LABEL: fptosi_v2f64_v2i64:
-; CHECK:       # %bb.0:
-; CHECK-NEXT:    vld $vr0, $a1, 0
-; CHECK-NEXT:    vftintrz.l.d $vr0, $vr0
-; CHECK-NEXT:    vst $vr0, $a0, 0
-; CHECK-NEXT:    ret
+; LA32-LABEL: fptosi_v2f64_v2i64:
+; LA32:       # %bb.0:
+; LA32-NEXT:    vld $vr0, $a1, 0
+; LA32-NEXT:    vftintrz.l.d $vr0, $vr0
+; LA32-NEXT:    vst $vr0, $a0, 0
+; LA32-NEXT:    ret
+;
+; LA64-LABEL: fptosi_v2f64_v2i64:
+; LA64:       # %bb.0:
+; LA64-NEXT:    vld $vr0, $a1, 0
+; LA64-NEXT:    vftintrz.l.d $vr0, $vr0
+; LA64-NEXT:    vst $vr0, $a0, 0
+; LA64-NEXT:    ret
   %v0 = load <2 x double>, ptr %in
   %v1 = fptosi <2 x double> %v0 to <2 x i64>
   store <2 x i64> %v1, ptr %res
   ret void
 }
+
+define void @fptosi_v2f64_v2i32(ptr %res, ptr %in){
+; LA32-LABEL: fptosi_v2f64_v2i32:
+; LA32:       # %bb.0:
+; LA32-NEXT:    vld $vr0, $a1, 0
+; LA32-NEXT:    vreplvei.d $vr1, $vr0, 0
+; LA32-NEXT:    ftintrz.w.d $fa1, $fa1
+; LA32-NEXT:    vreplvei.d $vr0, $vr0, 1
+; LA32-NEXT:    ftintrz.w.d $fa0, $fa0
+; LA32-NEXT:    fst.s $fa0, $a0, 4
+; LA32-NEXT:    fst.s $fa1, $a0, 0
+; LA32-NEXT:    ret
+;
+; LA64-LABEL: fptosi_v2f64_v2i32:
+; LA64:       # %bb.0:
+; LA64-NEXT:    vld $vr0, $a1, 0
+; LA64-NEXT:    vreplvei.d $vr1, $vr0, 0
+; LA64-NEXT:    ftintrz.w.d $fa1, $fa1
+; LA64-NEXT:    movfr2gr.s $a1, $fa1
+; LA64-NEXT:    vinsgr2vr.w $vr1, $a1, 0
+; LA64-NEXT:    vreplvei.d $vr0, $vr0, 1
+; LA64-NEXT:    ftintrz.w.d $fa0, $fa0
+; LA64-NEXT:    movfr2gr.s $a1, $fa0
+; LA64-NEXT:    vinsgr2vr.w $vr1, $a1, 1
+; LA64-NEXT:    vstelm.d $vr1, $a0, 0, 0
+; LA64-NEXT:    ret
+  %v0 = load <2 x double>, ptr %in
+  %v1 = fptosi <2 x double> %v0 to <2 x i32>
+  store <2 x i32> %v1, ptr %res
+  ret void
+}
+
+define void @fptosi_v4f64_v4i32(ptr %res, ptr %in){
+; LA32-LABEL: fptosi_v4f64_v4i32:
+; LA32:       # %bb.0:
+; LA32-NEXT:    vld $vr0, $a1, 0
+; LA32-NEXT:    vld $vr1, $a1, 16
+; LA32-NEXT:    vreplvei.d $vr2, $vr0, 0
+; LA32-NEXT:    ftintrz.w.d $fa2, $fa2
+; LA32-NEXT:    movfr2gr.s $a1, $fa2
+; LA32-NEXT:    vinsgr2vr.w $vr2, $a1, 0
+; LA32-NEXT:    vreplvei.d $vr0, $vr0, 1
+; LA32-NEXT:    ftintrz.w.d $fa0, $fa0
+; LA32-NEXT:    movfr2gr.s $a1, $fa0
+; LA32-NEXT:    vinsgr2vr.w $vr2, $a1, 1
+; LA32-NEXT:    vreplvei.d $vr0, $vr1, 0
+; LA32-NEXT:    ftintrz.w.d $fa0, $fa0
+; LA32-NEXT:    movfr2gr.s $a1, $fa0
+; LA32-NEXT:    vinsgr2vr.w $vr2, $a1, 2
+; LA32-NEXT:    vreplvei.d $vr0, $vr1, 1
+; LA32-NEXT:    ftintrz.w.d $fa0, $fa0
+; LA32-NEXT:    movfr2gr.s $a1, $fa0
+; LA32-NEXT:    vinsgr2vr.w $vr2, $a1, 3
+; LA32-NEXT:    vst $vr2, $a0, 0
+; LA32-NEXT:    ret
+;
+; LA64-LABEL: fptosi_v4f64_v4i32:
+; LA64:       # %bb.0:
+; LA64-NEXT:    vld $vr0, $a1, 0
+; LA64-NEXT:    vld $vr1, $a1, 16
+; LA64-NEXT:    vreplvei.d $vr2, $vr0, 0
+; LA64-NEXT:    ftintrz.w.d $fa2, $fa2
+; LA64-NEXT:    movfr2gr.s $a1, $fa2
+; LA64-NEXT:    vinsgr2vr.w $vr2, $a1, 0
+; LA64-NEXT:    vreplvei.d $vr0, $vr0, 1
+; LA64-NEXT:    ftintrz.w.d $fa0, $fa0
+; LA64-NEXT:    movfr2gr.s $a1, $fa0
+; LA64-NEXT:    vinsgr2vr.w $vr2, $a1, 1
+; LA64-NEXT:    vreplvei.d $vr0, $vr1, 0
+; LA64-NEXT:    ftintrz.w.d $fa0, $fa0
+; LA64-NEXT:    movfr2gr.s $a1, $fa0
+; LA64-NEXT:    vinsgr2vr.w $vr2, $a1, 2
+; LA64-NEXT:    vreplvei.d $vr0, $vr1, 1
+; LA64-NEXT:    ftintrz.w.d $fa0, $fa0
+; LA64-NEXT:    movfr2gr.s $a1, $fa0
+; LA64-NEXT:    vinsgr2vr.w $vr2, $a1, 3
+; LA64-NEXT:    vst $vr2, $a0, 0
+; LA64-NEXT:    ret
+  %v0 = load <4 x double>, ptr %in
+  %v1 = fptosi <4 x double> %v0 to <4 x i32>
+  store <4 x i32> %v1, ptr %res
+  ret void
+}
diff --git a/llvm/test/CodeGen/LoongArch/lsx/ir-instruction/fptoui.ll b/llvm/test/CodeGen/LoongArch/lsx/ir-instruction/fptoui.ll
index ec3a86713ed23..c2ead7f2dfe33 100644
--- a/llvm/test/CodeGen/LoongArch/lsx/ir-instruction/fptoui.ll
+++ b/llvm/test/CodeGen/LoongArch/lsx/ir-instruction/fptoui.ll
@@ -1,14 +1,21 @@
 ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 3
-; RUN: llc --mtriple=loongarch32 --mattr=+32s,+lsx < %s | FileCheck %s
-; RUN: llc --mtriple=loongarch64 --mattr=+lsx < %s | FileCheck %s
+; RUN: llc --mtriple=loongarch32 --mattr=+32s,+lsx < %s | FileCheck %s --check-prefix=LA32
+; RUN: llc --mtriple=loongarch64 --mattr=+lsx < %s | FileCheck %s --check-prefix=LA64
 
 define void @fptoui_v4f32_v4i32(ptr %res, ptr %in){
-; CHECK-LABEL: fptoui_v4f32_v4i32:
-; CHECK:       # %bb.0:
-; CHECK-NEXT:    vld $vr0, $a1, 0
-; CHECK-NEXT:    vftintrz.wu.s $vr0, $vr0
-; CHECK-NEXT:    vst $vr0, $a0, 0
-; CHECK-NEXT:    ret
+; LA32-LABEL: fptoui_v4f32_v4i32:
+; LA32:       # %bb.0:
+; LA32-NEXT:    vld $vr0, $a1, 0
+; LA32-NEXT:    vftintrz.wu.s $vr0, $vr0
+; LA32-NEXT:    vst $vr0, $a0, 0
+; LA32-NEXT:    ret
+;
+; LA64-LABEL: fptoui_v4f32_v4i32:
+; LA64:       # %bb.0:
+; LA64-NEXT:    vld $vr0, $a1, 0
+; LA64-NEXT:    vftintrz.wu.s $vr0, $vr0
+; LA64-NEXT:    vst $vr0, $a0, 0
+; LA64-NEXT:    ret
   %v0 = load <4 x float>, ptr %in
   %v1 = fptoui <4 x float> %v0 to <4 x i32>
   store <4 x i32> %v1, ptr %res
@@ -16,14 +23,168 @@ define void @fptoui_v4f32_v4i32(ptr %res, ptr %in){
 }
 
 define void @fptoui_v2f64_v2i64(ptr %res, ptr %in){
-; CHECK-LABEL: fptoui_v2f64_v2i64:
-; CHECK:       # %bb.0:
-; CHECK-NEXT:    vld $vr0, $a1, 0
-; CHECK-NEXT:    vftintrz.lu.d $vr0, $vr0
-; CHECK-NEXT:    vst $vr0, $a0, 0
-; CHECK-NEXT:    ret
+; LA32-LABEL: fptoui_v2f64_v2i64:
+; LA32:       # %bb.0:
+; LA32-NEXT:    vld $vr0, $a1, 0
+; LA32-NEXT:    vftintrz.lu.d $vr0, $vr0
+; LA32-NEXT:    vst $vr0, $a0, 0
+; LA32-NEXT:    ret
+;
+; LA64-LABEL: fptoui_v2f64_v2i64:
+; LA64:       # %bb.0:
+; LA64-NEXT:    vld $vr0, $a1, 0
+; LA64-NEXT:    vftintrz.lu.d $vr0, $vr0
+; LA64-NEXT:    vst $vr0, $a0, 0
+; LA64-NEXT:    ret
   %v0 = load <2 x double>, ptr %in
   %v1 = fptoui <2 x double> %v0 to <2 x i64>
   store <2 x i64> %v1, ptr %res
   ret void
 }
+
+define void @fptoui_v2f64_v2i32(ptr %res, ptr %in){
+; LA32-LABEL: fptoui_v2f64_v2i32:
+; LA32:       # %bb.0:
+; LA32-NEXT:    vld $vr0, $a1, 0
+; LA32-NEXT:    vreplvei.d $vr1, $vr0, 0
+; LA32-NEXT:    movgr2fr.w $fa2, $zero
+; LA32-NEXT:    lu12i.w $a1, 269824
+; LA32-NEXT:    movgr2frh.w $fa2, $a1
+; LA32-NEXT:    fcmp.clt.d $fcc0, $fa1, $fa2
+; LA32-NEXT:    fsub.d $fa3, $fa1, $fa2
+; LA32-NEXT:    ftintrz.w.d $fa3, $fa3
+; LA32-NEXT:    movfr2gr.s $a1, $fa3
+; LA32-NEXT:    lu12i.w $a2, -524288
+; LA32-NEXT:    xor $a1, $a1, $a2
+; LA32-NEXT:    movcf2gr $a3, $fcc0
+; LA32-NEXT:    masknez $a1, $a1, $a3
+; LA32-NEXT:    ftintrz.w.d $fa1, $fa1
+; LA32-NEXT:    movfr2gr.s $a4, $fa1
+; LA32-NEXT:    maskeqz $a3, $a4, $a3
+; LA32-NEXT:    or $a1, $a3, $a1
+; LA32-NEXT:    vreplvei.d $vr0, $vr0, 1
+; LA32-NEXT:    fcmp.clt.d $fcc0, $fa0, $fa2
+; LA32-NEXT:    fsub.d $fa1, $fa0, $fa2
+; LA32-NEXT:    ftintrz.w.d $fa1, $fa1
+; LA32-NEXT:    movfr2gr.s $a3, $fa1
+; LA32-NEXT:    xor $a2, $a3, $a2
+; LA32-NEXT:    movcf2gr $a3, $fcc0
+; LA32-NEXT:    masknez $a2, $a2, $a3
+; LA32-NEXT:    ftintrz.w.d $fa0, $fa0
+; LA32-NEXT:    movfr2gr.s $a4, $fa0
+; LA32-NEXT:    maskeqz $a3, $a4, $a3
+; LA32-NEXT:    or $a2, $a3, $a2
+; LA32-NEXT:    st.w $a2, $a0, 4
+; LA32-NEXT:    st.w $a1, $a0, 0
+; LA32-NEXT:    ret
+;
+; LA64-LABEL: fptoui_v2f64_v2i32:
+; LA64:       # %bb.0:
+; LA64-NEXT:    vld $vr0, $a1, 0
+; LA64-NEXT:    vreplvei.d $vr1, $vr0, 0
+; LA64-NEXT:    ftintrz.l.d $fa1, $fa1
+; LA64-NEXT:    movfr2gr.d $a1, $fa1
+; LA64-NEXT:    vinsgr2vr.w $vr1, $a1, 0
+; LA64-NEXT:    vreplvei.d $vr0, $vr0, 1
+; LA64-NEXT:    ftintrz.l.d $fa0, $fa0
+; LA64-NEXT:    movfr2gr.d $a1, $fa0
+; LA64-NEXT:    vinsgr2vr.w $vr1, $a1, 1
+; LA64-NEXT:    vstelm.d $vr1, $a0, 0, 0
+; LA64-NEXT:    ret
+  %v0 = load <2 x double>, ptr %in
+  %v1 = fptoui <2 x double> %v0 to <2 x i32>
+  store <2 x i32> %v1, ptr %res
+  ret void
+}
+
+define void @fptoui_v4f64_v4i32(ptr %res, ptr %in){
+; LA32-LABEL: fptoui_v4f64_v4i32:
+; LA32:       # %bb.0:
+; LA32-NEXT:    vld $vr0, $a1, 0
+; LA32-NEXT:    vld $vr1, $a1, 16
+; LA32-NEXT:    vreplvei.d $vr2, $vr0, 1
+; LA32-NEXT:    movgr2fr.w $fa3, $zero
+; LA32-NEXT:    lu12i.w $a1, 269824
+; LA32-NEXT:    movgr2frh.w $fa3, $a1
+; LA32-NEXT:    fcmp.clt.d $fcc0, $fa2, $fa3
+; LA32-NEXT:    fsub.d $fa4, $fa2, $fa3
+; LA32-NEXT:    ftintrz.w.d $fa4, $fa4
+; LA32-NEXT:    movfr2gr.s $a1, $fa4
+; LA32-NEXT:    lu12i.w $a2, -524288
+; LA32-NEXT:    xor $a1, $a1, $a2
+; LA32-NEXT:    movcf2gr $a3, $fcc0
+; LA32-NEXT:    masknez $a1, $a1, $a3
+; LA32-NEXT:    ftintrz.w.d $fa2, $fa2
+; LA32-NEXT:    movfr2gr.s $a4, $fa2
+; LA32-NEXT:    maskeqz $a3, $a4, $a3
+; LA32-NEXT:    or $a1, $a3, $a1
+; LA32-NEXT:    vreplvei.d $vr0, $vr0, 0
+; LA32-NEXT:    fcmp.clt.d $fcc0, $fa0, $fa3
+; LA32-NEXT:    fsub.d $fa2, $fa0, $fa3
+; LA32-NEXT:    ftintrz.w.d $fa2, $fa2
+; LA32-NEXT:    movfr2gr.s $a3, $fa2
+; LA32-NEXT:    xor $a3, $a3, $a2
+; LA32-NEXT:    movcf2gr $a4, $fcc0
+; LA32-NEXT:    masknez $a3, $a3, $a4
+; LA32-NEXT:    ftintrz.w.d $fa0, $fa0
+; LA32-NEXT:    movfr2gr.s $a5, $fa0
+; LA32-NEXT:    maskeqz $a4, $a5, $a4
+; LA32-NEXT:    or $a3, $a4, $a3
+; LA32-NEXT:    vinsgr2vr.w $vr0, $a3, 0
+; LA32-NEXT:    vinsgr2vr.w $vr0, $a1, 1
+; LA32-NEXT:    vreplvei.d $vr2, $vr1, 0
+; LA32-NEXT:    fcmp.clt.d $fcc0, $fa2, $fa3
+; LA32-NEXT:    fsub.d $fa4, $fa2, $fa3
+; LA32-NEXT:    ftintrz.w.d $fa4, $fa4
+; LA32-NEXT:    movfr2gr.s $a1, $fa4
+; LA32-NEXT:    xor $a1, $a1, $a2
+; LA32-NEXT:    movcf2gr $a3, $fcc0
+; LA32-NEXT:    masknez $a1, $a1, $a3
+; LA32-NEXT:    ftintrz.w.d $fa2, $fa2
+; LA32-NEXT:    movfr2gr.s $a4, $fa2
+; LA32-NEXT:    maskeqz $a3, $a4, $a3
+; LA32-NEXT:    or $a1, $a3, $a1
+; LA32-NEXT:    vinsgr2vr.w $vr0, $a1, 2
+; LA32-NEXT:    vreplvei.d $vr1, $vr1, 1
+; LA32-NEXT:    fcmp.clt.d $fcc0, $fa1, $fa3
+; LA32-NEXT:    fsub.d $fa2, $fa1, $fa3
+; LA32-NEXT:    ftintrz.w.d $fa2, $fa2
+; LA32-NEXT:    movfr2gr.s $a1, $fa2
+; LA32-NEXT:    xor $a1, $a1, $a2
+; LA32-NEXT:    movcf2gr $a2, $fcc0
+; LA32-NEXT:    masknez $a1, $a1, $a2
+; LA32-NEXT:    ftintrz.w.d $fa1, $fa1
+; LA32-NEXT:    movfr2gr.s $a3, $fa1
+; LA32-NEXT:    maskeqz $a2, $a3, $a2
+; LA32-NEXT:    or $a1, $a2, $a1
+; LA32-NEXT:    vinsgr2vr.w $vr0, $a1, 3
+; LA32-NEXT:    vst $vr0, $a0, 0
+; LA32-NEXT:    ret
+;
+; LA64-LABEL: fptoui_v4f64_v4i32:
+; LA64:       # %bb.0:
+; LA64-NEXT:    vld $vr0, $a1, 0
+; LA64-NEXT:    vld $vr1, $a1, 16
+; LA64-NEXT:    vreplvei.d $vr2, $vr0, 0
+; LA64-NEXT:    ftintrz.l.d $fa2, $fa2
+; LA64-NEXT:    movfr2gr.d $a1, $fa2
+; LA64-NEXT:    vinsgr2vr.w $vr2, $a1, 0
+; LA64-NEXT:    vreplvei.d $vr0, $vr0, 1
+; LA64-NEXT:    ftintrz.l.d $fa0, $fa0
+; LA64-NEXT:    movfr2gr.d $a1, $fa0
+; LA64-NEXT:    vinsgr2vr.w $vr2, $a1, 1
+; LA64-NEXT:    vreplvei.d $vr0, $vr1, 0
+; LA64-NEXT:    ftintrz.l.d $fa0, $fa0
+; LA64-NEXT:    movfr2gr.d $a1, $fa0
+; LA64-NEXT:    vinsgr2vr.w $vr2, $a1, 2
+; LA64-NEXT:    vreplvei.d $vr0, $vr1, 1
+; LA64-NEXT:    ftintrz.l.d $fa0, $fa0
+; LA64-NEXT:    movfr2gr.d $a1, $fa0
+; LA64-NEXT:    vinsgr2vr.w $vr2, $a1, 3
+; LA64-NEXT:    vst $vr2, $a0, 0
+; LA64-NEXT:    ret
+  %v0 = load <4 x double>, ptr %in
+  %v1 = fptoui <4 x double> %v0 to <4 x i32>
+  store <4 x i32> %v1, ptr %res
+  ret void
+}

>From c99ccb0a42e98c6934580c02592e4c8b438c0e8a Mon Sep 17 00:00:00 2001
From: Lin Runze <linrunze at loongson.cn>
Date: Thu, 4 Jun 2026 10:31:58 +0800
Subject: [PATCH 2/2] [LoongArch] Combine FP_TO_UINT/FP_TO_SINT with
 [X]VFTINTRZ instruction

---
 .../LoongArch/LoongArchISelLowering.cpp       | 102 ++++++++++++++
 .../LoongArch/LoongArchLASXInstrInfo.td       |   4 +
 .../Target/LoongArch/LoongArchLSXInstrInfo.td |   9 ++
 .../LoongArch/lasx/ir-instruction/fptosi.ll   |  20 +--
 .../LoongArch/lsx/ir-instruction/fptosi.ll    |  60 ++-------
 .../LoongArch/lsx/ir-instruction/fptoui.ll    | 125 ++----------------
 6 files changed, 147 insertions(+), 173 deletions(-)

diff --git a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
index 561064b3e1090..5b2f1b34cf50b 100644
--- a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
+++ b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
@@ -512,6 +512,8 @@ LoongArchTargetLowering::LoongArchTargetLowering(const TargetMachine &TM,
     setTargetDAGCombine(ISD::INTRINSIC_WO_CHAIN);
     setTargetDAGCombine(ISD::BITCAST);
     setTargetDAGCombine(ISD::VSELECT);
+    setTargetDAGCombine(ISD::FP_TO_SINT);
+    setTargetDAGCombine(ISD::FP_TO_UINT);
   }
 
   // Set DAG combine for 'LASX' feature.
@@ -7784,6 +7786,103 @@ static SDValue performSINT_TO_FPCombine(SDNode *N, SelectionDAG &DAG,
   return SDValue();
 }
 
+// Using [X]VFTINTRZ_W_D for double to signed 32-bit integer conversion.
+// For example:
+//   v4i32 = fp_to_sint (concat_vectors v2f64, v2f64)
+// Can be combined into:
+//   v4i32 = VFTINTRZ_W_D v2f64. v2f64
+static SDValue performFP_TO_INTCombine(SDNode *N, SelectionDAG &DAG,
+                                       TargetLowering::DAGCombinerInfo &DCI,
+                                       const LoongArchSubtarget &Subtarget) {
+  if (!Subtarget.hasExtLSX())
+    return SDValue();
+
+  SDLoc DL(N);
+  EVT DstVT = N->getValueType(0);
+  SDValue Src = N->getOperand(0);
+  EVT SrcVT = Src.getValueType();
+  bool IsSigned = N->getOpcode() == ISD::FP_TO_SINT;
+
+  if (!DstVT.isVector() || !DstVT.isSimple() || !SrcVT.isSimple())
+    return SDValue();
+
+  unsigned SrcEltBits = SrcVT.getScalarSizeInBits();
+  unsigned SrcBits = SrcVT.getSizeInBits();
+  unsigned DstEltBits = DstVT.getScalarSizeInBits();
+  unsigned NumElts = DstVT.getVectorNumElements();
+  unsigned BlockBits = Subtarget.hasExtLASX() ? 256 : 128;
+
+  if (!isPowerOf2_32(NumElts) || !isPowerOf2_32(DstEltBits))
+    return SDValue();
+
+  if (SrcBits % BlockBits != 0 && SrcBits != 128)
+    return SDValue();
+
+  if (DstEltBits < 32) {
+    MVT PromoteVT = MVT::getVectorVT(MVT::getIntegerVT(32), NumElts);
+    SDValue Conv = DAG.getNode(N->getOpcode(), DL, PromoteVT, Src);
+    return DAG.getNode(ISD::TRUNCATE, DL, DstVT, Conv);
+  }
+
+  if (SrcEltBits != 64 || DstEltBits != 32)
+    return SDValue();
+
+  if (!IsSigned) {
+    MVT TmpVT = MVT::getVectorVT(MVT::i64, NumElts);
+    SDValue Tmp = DAG.getNode(ISD::FP_TO_SINT, DL, TmpVT, Src);
+    return DAG.getNode(ISD::TRUNCATE, DL, DstVT, Tmp);
+  }
+
+  SmallVector<SDValue, 8> Blocks;
+  unsigned MidNumElts = BlockBits / SrcEltBits;
+  MVT MidVT = MVT::getVectorVT(MVT::getFloatingPointVT(SrcEltBits), MidNumElts);
+  if (Src.getOpcode() == ISD::CONCAT_VECTORS &&
+      Src.getOperand(0).getValueSizeInBits() == BlockBits) {
+    // Already split into per-register pieces by an earlier combine.
+    for (unsigned i = 0; i < Src.getNumOperands(); i++)
+      Blocks.push_back(Src.getOperand(i));
+  } else if (SrcBits > BlockBits) {
+    // Wider than one register: extract each BlockBits-wide sub-vector.
+    for (unsigned i = 0; i < SrcBits / BlockBits; i++)
+      Blocks.push_back(
+          DAG.getNode(ISD::EXTRACT_SUBVECTOR, DL, MidVT, Src,
+                      DAG.getVectorIdxConstant(i * MidNumElts, DL)));
+  } else if (SrcBits < BlockBits) {
+    // Narrower than one register: widen into a BlockBits register.
+    Blocks.push_back(DAG.getNode(ISD::INSERT_SUBVECTOR, DL, MidVT,
+                                 DAG.getUNDEF(MidVT), Src,
+                                 DAG.getVectorIdxConstant(0, DL)));
+  } else {
+    Blocks.push_back(Src);
+  }
+
+  MVT NativeVT = BlockBits == 256 ? MVT::v8i32 : MVT::v4i32;
+  bool IsValidUpperBits = SrcBits >= BlockBits;
+  bool SelfPair = Blocks.size() <= 1;
+
+  SmallVector<SDValue, 4> Parts;
+  for (unsigned i = 0; i < Blocks.size(); i += 2) {
+    SDValue Lo = Blocks[i];
+    SDValue Hi = SelfPair ? Lo : Blocks[i + 1];
+    SDValue Res = DAG.getNode(LoongArchISD::VFTINTRZ, DL, NativeVT, Hi, Lo);
+
+    if (BlockBits == 256 && IsValidUpperBits) {
+      Res = DAG.getBitcast(MVT::v4i64, Res);
+      Res = DAG.getNode(
+          LoongArchISD::XVPERMI, DL, MVT::v4i64, Res,
+          DAG.getConstant(0b11011000, DL, Subtarget.getGRLenVT()));
+      Res = DAG.getBitcast(NativeVT, Res);
+    }
+
+    Parts.push_back(Res);
+  }
+
+  if (SelfPair)
+    return DAG.getNode(ISD::EXTRACT_SUBVECTOR, DL, DstVT, Parts[0],
+                       DAG.getVectorIdxConstant(0, DL));
+  return DAG.getNode(ISD::CONCAT_VECTORS, DL, DstVT, Parts);
+}
+
 // Try to widen AND, OR and XOR nodes to VT in order to remove casts around
 // logical operations, like in the example below.
 //   or (and (truncate x, truncate y)),
@@ -8069,6 +8168,9 @@ SDValue LoongArchTargetLowering::PerformDAGCombine(SDNode *N,
     return performEXTENDCombine(N, DAG, DCI, Subtarget);
   case ISD::SINT_TO_FP:
     return performSINT_TO_FPCombine(N, DAG, DCI, Subtarget);
+  case ISD::FP_TO_SINT:
+  case ISD::FP_TO_UINT:
+    return performFP_TO_INTCombine(N, DAG, DCI, Subtarget);
   case LoongArchISD::BITREV_W:
     return performBITREV_WCombine(N, DAG, DCI, Subtarget);
   case LoongArchISD::BR_CC:
diff --git a/llvm/lib/Target/LoongArch/LoongArchLASXInstrInfo.td b/llvm/lib/Target/LoongArch/LoongArchLASXInstrInfo.td
index 0fb2b1d332f60..bea8da2188cc8 100644
--- a/llvm/lib/Target/LoongArch/LoongArchLASXInstrInfo.td
+++ b/llvm/lib/Target/LoongArch/LoongArchLASXInstrInfo.td
@@ -2120,6 +2120,10 @@ def : Pat<(v4i32(fp_to_uint v4f64:$vj)),
                (XVFTINTRZ_LU_D v4f64:$vj)),
               sub_128)>;
 
+// XVFTINTRZ_W_D
+def : Pat<(v8i32 (loongarch_vftintrz_w_d (v4f64 LASX256:$xj), (v4f64 LASX256:$xk))),
+          (XVFTINTRZ_W_D LASX256:$xj, LASX256:$xk)>;
+
 // XVAVG_{B/H/W/D/BU/HU/WU/DU}, XVAVGR_{B/H/W/D/BU/HU/WU/DU}
 defm : PatXrXr<avgfloors, "XVAVG">;
 defm : PatXrXr<avgceils, "XVAVGR">;
diff --git a/llvm/lib/Target/LoongArch/LoongArchLSXInstrInfo.td b/llvm/lib/Target/LoongArch/LoongArchLSXInstrInfo.td
index 34d4e2435b39d..6b10e52b4c655 100644
--- a/llvm/lib/Target/LoongArch/LoongArchLSXInstrInfo.td
+++ b/llvm/lib/Target/LoongArch/LoongArchLSXInstrInfo.td
@@ -36,6 +36,8 @@ def SDT_LoongArchVFCVT_S_D : SDTypeProfile<1, 2, [SDTCisVec<0>, SDTCisFP<0>,
                                                   SDTCisVec<1>, SDTCisFP<1>, SDTCisSameAs<1, 2>]>;
 def SDT_LoongArchVFCVTLH_D_S : SDTypeProfile<1, 1, [SDTCisVec<0>, SDTCisFP<0>,
                                                     SDTCisVec<1>, SDTCisFP<1>]>;
+def SDT_LoongArchVFTINTRZ_W_D : SDTypeProfile<1, 2, [SDTCisVec<0>, SDTCisInt<0>,
+                                                     SDTCisVec<1>, SDTCisFP<1>, SDTCisSameAs<1, 2>]>;
 
 // Target nodes.
 
@@ -107,6 +109,9 @@ def loongarch_vfcvth_d_s: SDNode<"LoongArchISD::VFCVTH", SDT_LoongArchVFCVTLH_D_
 def loongarch_vsrlr: SDNode<"LoongArchISD::VSRLR", SDT_LoongArchV2R>;
 def loongarch_vsrar: SDNode<"LoongArchISD::VSRAR", SDT_LoongArchV2R>;
 
+// Vector double-precision convert to 32-bit integer
+def loongarch_vftintrz_w_d: SDNode<"LoongArchISD::VFTINTRZ", SDT_LoongArchVFTINTRZ_W_D>;
+
 def immZExt1 : ImmLeaf<GRLenVT, [{return isUInt<1>(Imm);}]>;
 def immZExt2 : ImmLeaf<GRLenVT, [{return isUInt<2>(Imm);}]>;
 def immZExt3 : ImmLeaf<GRLenVT, [{return isUInt<3>(Imm);}]>;
@@ -2300,6 +2305,10 @@ def : Pat<(v2i64 (fp_to_sint v2f64:$vj)), (VFTINTRZ_L_D v2f64:$vj)>;
 def : Pat<(v4i32 (fp_to_uint v4f32:$vj)), (VFTINTRZ_WU_S v4f32:$vj)>;
 def : Pat<(v2i64 (fp_to_uint v2f64:$vj)), (VFTINTRZ_LU_D v2f64:$vj)>;
 
+// VFTINTRZ_W_D
+def : Pat<(v4i32 (loongarch_vftintrz_w_d (v2f64 LSX128:$vj), (v2f64 LSX128:$vk))),
+          (VFTINTRZ_W_D LSX128:$vj, LSX128:$vk)>;
+
 // Vector loads floating-point constants
 def : Pat<(f32 f32imm_vldi:$in),
           (f32 (EXTRACT_SUBREG (VLDI (to_f32imm_vldi f32imm_vldi:$in)), sub_32))>;
diff --git a/llvm/test/CodeGen/LoongArch/lasx/ir-instruction/fptosi.ll b/llvm/test/CodeGen/LoongArch/lasx/ir-instruction/fptosi.ll
index 861052b0ffec1..17a4c23dd3e1d 100644
--- a/llvm/test/CodeGen/LoongArch/lasx/ir-instruction/fptosi.ll
+++ b/llvm/test/CodeGen/LoongArch/lasx/ir-instruction/fptosi.ll
@@ -32,9 +32,8 @@ define void @fptosi_v4f64_v4i32(ptr %res, ptr %in){
 ; CHECK-LABEL: fptosi_v4f64_v4i32:
 ; CHECK:       # %bb.0:
 ; CHECK-NEXT:    xvld $xr0, $a1, 0
-; CHECK-NEXT:    xvftintrz.l.d $xr0, $xr0
-; CHECK-NEXT:    xvpermi.d $xr1, $xr0, 238
-; CHECK-NEXT:    xvpickev.w $xr0, $xr1, $xr0
+; CHECK-NEXT:    xvftintrz.w.d $xr0, $xr0, $xr0
+; CHECK-NEXT:    xvpermi.d $xr0, $xr0, 216
 ; CHECK-NEXT:    vst $vr0, $a0, 0
 ; CHECK-NEXT:    ret
   %v0 = load <4 x double>, ptr %in
@@ -46,16 +45,11 @@ define void @fptosi_v4f64_v4i32(ptr %res, ptr %in){
 define void @fptosi_v8f64_v8i32(ptr %res, ptr %in){
 ; CHECK-LABEL: fptosi_v8f64_v8i32:
 ; CHECK:       # %bb.0:
-; CHECK-NEXT:    xvld $xr0, $a1, 32
-; CHECK-NEXT:    xvld $xr1, $a1, 0
-; CHECK-NEXT:    xvftintrz.l.d $xr0, $xr0
-; CHECK-NEXT:    xvpermi.d $xr2, $xr0, 238
-; CHECK-NEXT:    xvpickev.w $xr0, $xr2, $xr0
-; CHECK-NEXT:    xvftintrz.l.d $xr1, $xr1
-; CHECK-NEXT:    xvpermi.d $xr2, $xr1, 238
-; CHECK-NEXT:    xvpickev.w $xr1, $xr2, $xr1
-; CHECK-NEXT:    xvpermi.q $xr1, $xr0, 2
-; CHECK-NEXT:    xvst $xr1, $a0, 0
+; CHECK-NEXT:    xvld $xr0, $a1, 0
+; CHECK-NEXT:    xvld $xr1, $a1, 32
+; CHECK-NEXT:    xvftintrz.w.d $xr0, $xr1, $xr0
+; CHECK-NEXT:    xvpermi.d $xr0, $xr0, 216
+; CHECK-NEXT:    xvst $xr0, $a0, 0
 ; CHECK-NEXT:    ret
   %v0 = load <8 x double>, ptr %in
   %v1 = fptosi <8 x double> %v0 to <8 x i32>
diff --git a/llvm/test/CodeGen/LoongArch/lsx/ir-instruction/fptosi.ll b/llvm/test/CodeGen/LoongArch/lsx/ir-instruction/fptosi.ll
index 76bc8225a4ae8..4989733d734b6 100644
--- a/llvm/test/CodeGen/LoongArch/lsx/ir-instruction/fptosi.ll
+++ b/llvm/test/CodeGen/LoongArch/lsx/ir-instruction/fptosi.ll
@@ -46,26 +46,18 @@ define void @fptosi_v2f64_v2i32(ptr %res, ptr %in){
 ; LA32-LABEL: fptosi_v2f64_v2i32:
 ; LA32:       # %bb.0:
 ; LA32-NEXT:    vld $vr0, $a1, 0
-; LA32-NEXT:    vreplvei.d $vr1, $vr0, 0
-; LA32-NEXT:    ftintrz.w.d $fa1, $fa1
-; LA32-NEXT:    vreplvei.d $vr0, $vr0, 1
-; LA32-NEXT:    ftintrz.w.d $fa0, $fa0
-; LA32-NEXT:    fst.s $fa0, $a0, 4
-; LA32-NEXT:    fst.s $fa1, $a0, 0
+; LA32-NEXT:    vftintrz.w.d $vr0, $vr0, $vr0
+; LA32-NEXT:    vpickve2gr.w $a1, $vr0, 1
+; LA32-NEXT:    st.w $a1, $a0, 4
+; LA32-NEXT:    vpickve2gr.w $a1, $vr0, 0
+; LA32-NEXT:    st.w $a1, $a0, 0
 ; LA32-NEXT:    ret
 ;
 ; LA64-LABEL: fptosi_v2f64_v2i32:
 ; LA64:       # %bb.0:
 ; LA64-NEXT:    vld $vr0, $a1, 0
-; LA64-NEXT:    vreplvei.d $vr1, $vr0, 0
-; LA64-NEXT:    ftintrz.w.d $fa1, $fa1
-; LA64-NEXT:    movfr2gr.s $a1, $fa1
-; LA64-NEXT:    vinsgr2vr.w $vr1, $a1, 0
-; LA64-NEXT:    vreplvei.d $vr0, $vr0, 1
-; LA64-NEXT:    ftintrz.w.d $fa0, $fa0
-; LA64-NEXT:    movfr2gr.s $a1, $fa0
-; LA64-NEXT:    vinsgr2vr.w $vr1, $a1, 1
-; LA64-NEXT:    vstelm.d $vr1, $a0, 0, 0
+; LA64-NEXT:    vftintrz.w.d $vr0, $vr0, $vr0
+; LA64-NEXT:    vstelm.d $vr0, $a0, 0, 0
 ; LA64-NEXT:    ret
   %v0 = load <2 x double>, ptr %in
   %v1 = fptosi <2 x double> %v0 to <2 x i32>
@@ -78,46 +70,16 @@ define void @fptosi_v4f64_v4i32(ptr %res, ptr %in){
 ; LA32:       # %bb.0:
 ; LA32-NEXT:    vld $vr0, $a1, 0
 ; LA32-NEXT:    vld $vr1, $a1, 16
-; LA32-NEXT:    vreplvei.d $vr2, $vr0, 0
-; LA32-NEXT:    ftintrz.w.d $fa2, $fa2
-; LA32-NEXT:    movfr2gr.s $a1, $fa2
-; LA32-NEXT:    vinsgr2vr.w $vr2, $a1, 0
-; LA32-NEXT:    vreplvei.d $vr0, $vr0, 1
-; LA32-NEXT:    ftintrz.w.d $fa0, $fa0
-; LA32-NEXT:    movfr2gr.s $a1, $fa0
-; LA32-NEXT:    vinsgr2vr.w $vr2, $a1, 1
-; LA32-NEXT:    vreplvei.d $vr0, $vr1, 0
-; LA32-NEXT:    ftintrz.w.d $fa0, $fa0
-; LA32-NEXT:    movfr2gr.s $a1, $fa0
-; LA32-NEXT:    vinsgr2vr.w $vr2, $a1, 2
-; LA32-NEXT:    vreplvei.d $vr0, $vr1, 1
-; LA32-NEXT:    ftintrz.w.d $fa0, $fa0
-; LA32-NEXT:    movfr2gr.s $a1, $fa0
-; LA32-NEXT:    vinsgr2vr.w $vr2, $a1, 3
-; LA32-NEXT:    vst $vr2, $a0, 0
+; LA32-NEXT:    vftintrz.w.d $vr0, $vr1, $vr0
+; LA32-NEXT:    vst $vr0, $a0, 0
 ; LA32-NEXT:    ret
 ;
 ; LA64-LABEL: fptosi_v4f64_v4i32:
 ; LA64:       # %bb.0:
 ; LA64-NEXT:    vld $vr0, $a1, 0
 ; LA64-NEXT:    vld $vr1, $a1, 16
-; LA64-NEXT:    vreplvei.d $vr2, $vr0, 0
-; LA64-NEXT:    ftintrz.w.d $fa2, $fa2
-; LA64-NEXT:    movfr2gr.s $a1, $fa2
-; LA64-NEXT:    vinsgr2vr.w $vr2, $a1, 0
-; LA64-NEXT:    vreplvei.d $vr0, $vr0, 1
-; LA64-NEXT:    ftintrz.w.d $fa0, $fa0
-; LA64-NEXT:    movfr2gr.s $a1, $fa0
-; LA64-NEXT:    vinsgr2vr.w $vr2, $a1, 1
-; LA64-NEXT:    vreplvei.d $vr0, $vr1, 0
-; LA64-NEXT:    ftintrz.w.d $fa0, $fa0
-; LA64-NEXT:    movfr2gr.s $a1, $fa0
-; LA64-NEXT:    vinsgr2vr.w $vr2, $a1, 2
-; LA64-NEXT:    vreplvei.d $vr0, $vr1, 1
-; LA64-NEXT:    ftintrz.w.d $fa0, $fa0
-; LA64-NEXT:    movfr2gr.s $a1, $fa0
-; LA64-NEXT:    vinsgr2vr.w $vr2, $a1, 3
-; LA64-NEXT:    vst $vr2, $a0, 0
+; LA64-NEXT:    vftintrz.w.d $vr0, $vr1, $vr0
+; LA64-NEXT:    vst $vr0, $a0, 0
 ; LA64-NEXT:    ret
   %v0 = load <4 x double>, ptr %in
   %v1 = fptosi <4 x double> %v0 to <4 x i32>
diff --git a/llvm/test/CodeGen/LoongArch/lsx/ir-instruction/fptoui.ll b/llvm/test/CodeGen/LoongArch/lsx/ir-instruction/fptoui.ll
index c2ead7f2dfe33..28aac2c042cc3 100644
--- a/llvm/test/CodeGen/LoongArch/lsx/ir-instruction/fptoui.ll
+++ b/llvm/test/CodeGen/LoongArch/lsx/ir-instruction/fptoui.ll
@@ -46,50 +46,19 @@ define void @fptoui_v2f64_v2i32(ptr %res, ptr %in){
 ; LA32-LABEL: fptoui_v2f64_v2i32:
 ; LA32:       # %bb.0:
 ; LA32-NEXT:    vld $vr0, $a1, 0
-; LA32-NEXT:    vreplvei.d $vr1, $vr0, 0
-; LA32-NEXT:    movgr2fr.w $fa2, $zero
-; LA32-NEXT:    lu12i.w $a1, 269824
-; LA32-NEXT:    movgr2frh.w $fa2, $a1
-; LA32-NEXT:    fcmp.clt.d $fcc0, $fa1, $fa2
-; LA32-NEXT:    fsub.d $fa3, $fa1, $fa2
-; LA32-NEXT:    ftintrz.w.d $fa3, $fa3
-; LA32-NEXT:    movfr2gr.s $a1, $fa3
-; LA32-NEXT:    lu12i.w $a2, -524288
-; LA32-NEXT:    xor $a1, $a1, $a2
-; LA32-NEXT:    movcf2gr $a3, $fcc0
-; LA32-NEXT:    masknez $a1, $a1, $a3
-; LA32-NEXT:    ftintrz.w.d $fa1, $fa1
-; LA32-NEXT:    movfr2gr.s $a4, $fa1
-; LA32-NEXT:    maskeqz $a3, $a4, $a3
-; LA32-NEXT:    or $a1, $a3, $a1
-; LA32-NEXT:    vreplvei.d $vr0, $vr0, 1
-; LA32-NEXT:    fcmp.clt.d $fcc0, $fa0, $fa2
-; LA32-NEXT:    fsub.d $fa1, $fa0, $fa2
-; LA32-NEXT:    ftintrz.w.d $fa1, $fa1
-; LA32-NEXT:    movfr2gr.s $a3, $fa1
-; LA32-NEXT:    xor $a2, $a3, $a2
-; LA32-NEXT:    movcf2gr $a3, $fcc0
-; LA32-NEXT:    masknez $a2, $a2, $a3
-; LA32-NEXT:    ftintrz.w.d $fa0, $fa0
-; LA32-NEXT:    movfr2gr.s $a4, $fa0
-; LA32-NEXT:    maskeqz $a3, $a4, $a3
-; LA32-NEXT:    or $a2, $a3, $a2
-; LA32-NEXT:    st.w $a2, $a0, 4
+; LA32-NEXT:    vftintrz.l.d $vr0, $vr0
+; LA32-NEXT:    vpickve2gr.w $a1, $vr0, 2
+; LA32-NEXT:    st.w $a1, $a0, 4
+; LA32-NEXT:    vpickve2gr.w $a1, $vr0, 0
 ; LA32-NEXT:    st.w $a1, $a0, 0
 ; LA32-NEXT:    ret
 ;
 ; LA64-LABEL: fptoui_v2f64_v2i32:
 ; LA64:       # %bb.0:
 ; LA64-NEXT:    vld $vr0, $a1, 0
-; LA64-NEXT:    vreplvei.d $vr1, $vr0, 0
-; LA64-NEXT:    ftintrz.l.d $fa1, $fa1
-; LA64-NEXT:    movfr2gr.d $a1, $fa1
-; LA64-NEXT:    vinsgr2vr.w $vr1, $a1, 0
-; LA64-NEXT:    vreplvei.d $vr0, $vr0, 1
-; LA64-NEXT:    ftintrz.l.d $fa0, $fa0
-; LA64-NEXT:    movfr2gr.d $a1, $fa0
-; LA64-NEXT:    vinsgr2vr.w $vr1, $a1, 1
-; LA64-NEXT:    vstelm.d $vr1, $a0, 0, 0
+; LA64-NEXT:    vftintrz.l.d $vr0, $vr0
+; LA64-NEXT:    vshuf4i.w $vr0, $vr0, 8
+; LA64-NEXT:    vstelm.d $vr0, $a0, 0, 0
 ; LA64-NEXT:    ret
   %v0 = load <2 x double>, ptr %in
   %v1 = fptoui <2 x double> %v0 to <2 x i32>
@@ -102,62 +71,9 @@ define void @fptoui_v4f64_v4i32(ptr %res, ptr %in){
 ; LA32:       # %bb.0:
 ; LA32-NEXT:    vld $vr0, $a1, 0
 ; LA32-NEXT:    vld $vr1, $a1, 16
-; LA32-NEXT:    vreplvei.d $vr2, $vr0, 1
-; LA32-NEXT:    movgr2fr.w $fa3, $zero
-; LA32-NEXT:    lu12i.w $a1, 269824
-; LA32-NEXT:    movgr2frh.w $fa3, $a1
-; LA32-NEXT:    fcmp.clt.d $fcc0, $fa2, $fa3
-; LA32-NEXT:    fsub.d $fa4, $fa2, $fa3
-; LA32-NEXT:    ftintrz.w.d $fa4, $fa4
-; LA32-NEXT:    movfr2gr.s $a1, $fa4
-; LA32-NEXT:    lu12i.w $a2, -524288
-; LA32-NEXT:    xor $a1, $a1, $a2
-; LA32-NEXT:    movcf2gr $a3, $fcc0
-; LA32-NEXT:    masknez $a1, $a1, $a3
-; LA32-NEXT:    ftintrz.w.d $fa2, $fa2
-; LA32-NEXT:    movfr2gr.s $a4, $fa2
-; LA32-NEXT:    maskeqz $a3, $a4, $a3
-; LA32-NEXT:    or $a1, $a3, $a1
-; LA32-NEXT:    vreplvei.d $vr0, $vr0, 0
-; LA32-NEXT:    fcmp.clt.d $fcc0, $fa0, $fa3
-; LA32-NEXT:    fsub.d $fa2, $fa0, $fa3
-; LA32-NEXT:    ftintrz.w.d $fa2, $fa2
-; LA32-NEXT:    movfr2gr.s $a3, $fa2
-; LA32-NEXT:    xor $a3, $a3, $a2
-; LA32-NEXT:    movcf2gr $a4, $fcc0
-; LA32-NEXT:    masknez $a3, $a3, $a4
-; LA32-NEXT:    ftintrz.w.d $fa0, $fa0
-; LA32-NEXT:    movfr2gr.s $a5, $fa0
-; LA32-NEXT:    maskeqz $a4, $a5, $a4
-; LA32-NEXT:    or $a3, $a4, $a3
-; LA32-NEXT:    vinsgr2vr.w $vr0, $a3, 0
-; LA32-NEXT:    vinsgr2vr.w $vr0, $a1, 1
-; LA32-NEXT:    vreplvei.d $vr2, $vr1, 0
-; LA32-NEXT:    fcmp.clt.d $fcc0, $fa2, $fa3
-; LA32-NEXT:    fsub.d $fa4, $fa2, $fa3
-; LA32-NEXT:    ftintrz.w.d $fa4, $fa4
-; LA32-NEXT:    movfr2gr.s $a1, $fa4
-; LA32-NEXT:    xor $a1, $a1, $a2
-; LA32-NEXT:    movcf2gr $a3, $fcc0
-; LA32-NEXT:    masknez $a1, $a1, $a3
-; LA32-NEXT:    ftintrz.w.d $fa2, $fa2
-; LA32-NEXT:    movfr2gr.s $a4, $fa2
-; LA32-NEXT:    maskeqz $a3, $a4, $a3
-; LA32-NEXT:    or $a1, $a3, $a1
-; LA32-NEXT:    vinsgr2vr.w $vr0, $a1, 2
-; LA32-NEXT:    vreplvei.d $vr1, $vr1, 1
-; LA32-NEXT:    fcmp.clt.d $fcc0, $fa1, $fa3
-; LA32-NEXT:    fsub.d $fa2, $fa1, $fa3
-; LA32-NEXT:    ftintrz.w.d $fa2, $fa2
-; LA32-NEXT:    movfr2gr.s $a1, $fa2
-; LA32-NEXT:    xor $a1, $a1, $a2
-; LA32-NEXT:    movcf2gr $a2, $fcc0
-; LA32-NEXT:    masknez $a1, $a1, $a2
-; LA32-NEXT:    ftintrz.w.d $fa1, $fa1
-; LA32-NEXT:    movfr2gr.s $a3, $fa1
-; LA32-NEXT:    maskeqz $a2, $a3, $a2
-; LA32-NEXT:    or $a1, $a2, $a1
-; LA32-NEXT:    vinsgr2vr.w $vr0, $a1, 3
+; LA32-NEXT:    vftintrz.l.d $vr0, $vr0
+; LA32-NEXT:    vftintrz.l.d $vr1, $vr1
+; LA32-NEXT:    vpickev.w $vr0, $vr1, $vr0
 ; LA32-NEXT:    vst $vr0, $a0, 0
 ; LA32-NEXT:    ret
 ;
@@ -165,23 +81,10 @@ define void @fptoui_v4f64_v4i32(ptr %res, ptr %in){
 ; LA64:       # %bb.0:
 ; LA64-NEXT:    vld $vr0, $a1, 0
 ; LA64-NEXT:    vld $vr1, $a1, 16
-; LA64-NEXT:    vreplvei.d $vr2, $vr0, 0
-; LA64-NEXT:    ftintrz.l.d $fa2, $fa2
-; LA64-NEXT:    movfr2gr.d $a1, $fa2
-; LA64-NEXT:    vinsgr2vr.w $vr2, $a1, 0
-; LA64-NEXT:    vreplvei.d $vr0, $vr0, 1
-; LA64-NEXT:    ftintrz.l.d $fa0, $fa0
-; LA64-NEXT:    movfr2gr.d $a1, $fa0
-; LA64-NEXT:    vinsgr2vr.w $vr2, $a1, 1
-; LA64-NEXT:    vreplvei.d $vr0, $vr1, 0
-; LA64-NEXT:    ftintrz.l.d $fa0, $fa0
-; LA64-NEXT:    movfr2gr.d $a1, $fa0
-; LA64-NEXT:    vinsgr2vr.w $vr2, $a1, 2
-; LA64-NEXT:    vreplvei.d $vr0, $vr1, 1
-; LA64-NEXT:    ftintrz.l.d $fa0, $fa0
-; LA64-NEXT:    movfr2gr.d $a1, $fa0
-; LA64-NEXT:    vinsgr2vr.w $vr2, $a1, 3
-; LA64-NEXT:    vst $vr2, $a0, 0
+; LA64-NEXT:    vftintrz.l.d $vr0, $vr0
+; LA64-NEXT:    vftintrz.l.d $vr1, $vr1
+; LA64-NEXT:    vpickev.w $vr0, $vr1, $vr0
+; LA64-NEXT:    vst $vr0, $a0, 0
 ; LA64-NEXT:    ret
   %v0 = load <4 x double>, ptr %in
   %v1 = fptoui <4 x double> %v0 to <4 x i32>



More information about the llvm-commits mailing list