[llvm-branch-commits] [llvm] [SelectionDAG] Fix incorrect expansion of `CONVERT_TO_ARBITRARY_FP` (PR #221358)

Min-Yih Hsu via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Fri Sep 4 15:25:27 PDT 2026


https://github.com/mshockwave updated https://github.com/llvm/llvm-project/pull/221358

>From ea908bf4324f72dd4f6d6a9ceb8243e8e5616588 Mon Sep 17 00:00:00 2001
From: Min-Yih Hsu <min.hsu at sifive.com>
Date: Wed, 26 Aug 2026 11:53:16 -0700
Subject: [PATCH 1/2] [SelectionDAG] Fix incorrect expansion of
 `CONVERT_TO_ARBITRARY_FP`

---
 .../CodeGen/SelectionDAG/TargetLowering.cpp   |  61 +-
 .../CodeGen/RISCV/convert-to-arbitrary-fp.ll  | 826 ++++++++++++++++++
 2 files changed, 875 insertions(+), 12 deletions(-)
 create mode 100644 llvm/test/CodeGen/RISCV/convert-to-arbitrary-fp.ll

diff --git a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
index 16f91bb50e717..ceeceafa40fec 100644
--- a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
@@ -9357,6 +9357,16 @@ SDValue TargetLowering::expandCONVERT_TO_ARBITRARY_FP(SDNode *Node,
   // expansion stays vector when ResVT is a vector.
   EVT IntScalarVT = EVT::getIntegerVT(*DAG.getContext(), SrcBits);
   EVT IntVT = ResVT.changeElementType(*DAG.getContext(), IntScalarVT);
+  if (!IntVT.isVector() && !isTypeLegal(IntScalarVT)) {
+    if (getTypeAction(*DAG.getContext(), IntScalarVT) != TypePromoteInteger) {
+      // We only know how to handle situations where the legal type is wider.
+      DAG.getContext()->emitError(
+          "CONVERT_TO_ARBITRARY_FP: the requested integer value type for its "
+          "legalization is not supported");
+      return SDValue();
+    }
+    IntVT = getTypeToTransformTo(*DAG.getContext(), IntScalarVT);
+  }
   EVT SetCCVT =
       getSetCCResultType(DAG.getDataLayout(), *DAG.getContext(), IntVT);
   EVT FPSetCCVT =
@@ -9365,8 +9375,17 @@ SDValue TargetLowering::expandCONVERT_TO_ARBITRARY_FP(SDNode *Node,
   SDValue Zero = DAG.getConstant(0, dl, IntVT);
   SDValue One = DAG.getConstant(1, dl, IntVT);
 
-  // Bitcast source float to integer to extract the sign bit.
-  SDValue Src = DAG.getNode(ISD::BITCAST, dl, IntVT, FloatVal);
+  SDValue Src;
+  if (!IntVT.bitsEq(SrcVT)) {
+    // Store to stack before loading it back.
+    assert(!IntVT.isVector() && IntVT.bitsGT(SrcVT));
+    // IntScalarVT is the original type that has the same width as SrcVT.
+    Src = DAG.emitStackConvert(FloatVal, IntScalarVT, IntVT, dl,
+                               DAG.getEntryNode());
+  } else {
+    // Bitcast source float to integer to extract the sign bit.
+    Src = DAG.getNode(ISD::BITCAST, dl, IntVT, FloatVal);
+  }
   SDValue SignBit =
       DAG.getNode(ISD::SRL, dl, IntVT, Src,
                   DAG.getShiftAmountConstant(SrcBits - 1, IntVT, dl));
@@ -9385,12 +9404,31 @@ SDValue TargetLowering::expandCONVERT_TO_ARBITRARY_FP(SDNode *Node,
   EVT FrexpExpScalarVT =
       getValueType(DAG.getDataLayout(), Type::getInt32Ty(*DAG.getContext()));
   EVT FrexpExpVT = SrcVT.changeElementType(*DAG.getContext(), FrexpExpScalarVT);
+  if (!FrexpExpVT.isVector() && !isTypeLegal(FrexpExpVT)) {
+    if (getTypeAction(*DAG.getContext(), FrexpExpScalarVT) !=
+        TypePromoteInteger) {
+      // We only know how to handle situations where the legal type is wider.
+      DAG.getContext()->emitError("CONVERT_TO_ARBITRARY_FP: the requested i32 "
+                                  "type for its legalization is not supported");
+      return SDValue();
+    }
+    FrexpExpVT = getTypeToTransformTo(*DAG.getContext(), FrexpExpScalarVT);
+  }
   SDValue Frexp =
       DAG.getNode(ISD::FFREXP, dl, DAG.getVTList(SrcVT, FrexpExpVT), FloatVal);
   SDValue FrexpFrac = Frexp.getValue(0);
   SDValue FrexpExp = Frexp.getValue(1);
 
-  SDValue FrexpFracInt = DAG.getNode(ISD::BITCAST, dl, IntVT, FrexpFrac);
+  SDValue FrexpFracInt;
+  if (!IntVT.bitsEq(SrcVT)) {
+    // Store to stack before loading it back.
+    assert(!IntVT.isVector() && IntVT.bitsGT(SrcVT));
+    // IntScalarVT is the original type that has the same width as SrcVT.
+    FrexpFracInt = DAG.emitStackConvert(FrexpFrac, IntScalarVT, IntVT, dl,
+                                        DAG.getEntryNode());
+  } else {
+    FrexpFracInt = DAG.getNode(ISD::BITCAST, dl, IntVT, FrexpFrac);
+  }
   SDValue EffSrcMant = DAG.getNode(ISD::AND, dl, IntVT, FrexpFracInt,
                                    DAG.getConstant(SrcMantMask, dl, IntVT));
 
@@ -9419,7 +9457,7 @@ SDValue TargetLowering::expandCONVERT_TO_ARBITRARY_FP(SDNode *Node,
       SDValue IsPositive = DAG.getSetCC(dl, SetCCVT, SignBit, Zero, ISD::SETEQ);
       SDValue DoRound =
           DAG.getNode(ISD::AND, dl, SetCCVT, HasTruncBits, IsPositive);
-      return DAG.getNode(ISD::ZERO_EXTEND, dl, IntVT, DoRound);
+      return DAG.getZExtOrTrunc(DoRound, dl, IntVT);
     }
     case RoundingMode::TowardNegative: {
       // Round up if negative and any truncated bits are set (to -Inf).
@@ -9430,7 +9468,7 @@ SDValue TargetLowering::expandCONVERT_TO_ARBITRARY_FP(SDNode *Node,
       SDValue IsNegative = DAG.getSetCC(dl, SetCCVT, SignBit, Zero, ISD::SETNE);
       SDValue DoRound =
           DAG.getNode(ISD::AND, dl, SetCCVT, HasTruncBits, IsNegative);
-      return DAG.getNode(ISD::ZERO_EXTEND, dl, IntVT, DoRound);
+      return DAG.getZExtOrTrunc(DoRound, dl, IntVT);
     }
     case RoundingMode::NearestTiesToAway:
       return RoundBit;
@@ -9465,7 +9503,7 @@ SDValue TargetLowering::expandCONVERT_TO_ARBITRARY_FP(SDNode *Node,
       StickyBits = DAG.getNode(ISD::AND, dl, IntVT, EffSrcMant,
                                DAG.getConstant(StickyMask, dl, IntVT));
       StickyBits = DAG.getSetCC(dl, SetCCVT, StickyBits, Zero, ISD::SETNE);
-      StickyBits = DAG.getNode(ISD::ZERO_EXTEND, dl, IntVT, StickyBits);
+      StickyBits = DAG.getZExtOrTrunc(StickyBits, dl, IntVT);
     } else {
       StickyBits = Zero;
     }
@@ -9492,9 +9530,8 @@ SDValue TargetLowering::expandCONVERT_TO_ARBITRARY_FP(SDNode *Node,
                    DAG.getConstant(DstMantMask, dl, IntVT), ISD::SETGT);
   // On overflow: mant = 0, exp += 1.
   SDValue AdjMant = DAG.getSelect(dl, IntVT, MantOverflow, Zero, RoundedMant);
-  SDValue AdjExp =
-      DAG.getNode(ISD::ADD, dl, IntVT, NewExp,
-                  DAG.getNode(ISD::ZERO_EXTEND, dl, IntVT, MantOverflow));
+  SDValue AdjExp = DAG.getNode(ISD::ADD, dl, IntVT, NewExp,
+                               DAG.getZExtOrTrunc(MantOverflow, dl, IntVT));
 
   // Precompute sign shifted to MSB of destination. Unsigned formats have no
   // sign bit to merge in.
@@ -9557,9 +9594,9 @@ SDValue TargetLowering::expandCONVERT_TO_ARBITRARY_FP(SDNode *Node,
           DAG.getNode(ISD::SHL, dl, IntVT, One, RoundBitPosAmt), One);
       SDValue DenormStickyBits =
           DAG.getNode(ISD::AND, dl, IntVT, FullSrcMant, StickyMask);
-      SDValue HasSticky = DAG.getNode(
-          ISD::ZERO_EXTEND, dl, IntVT,
-          DAG.getSetCC(dl, SetCCVT, DenormStickyBits, Zero, ISD::SETNE));
+      SDValue HasSticky = DAG.getZExtOrTrunc(
+          DAG.getSetCC(dl, SetCCVT, DenormStickyBits, Zero, ISD::SETNE), dl,
+          IntVT);
 
       SDValue DenormLSB =
           DAG.getNode(ISD::AND, dl, IntVT, DenormTruncMant, One);
diff --git a/llvm/test/CodeGen/RISCV/convert-to-arbitrary-fp.ll b/llvm/test/CodeGen/RISCV/convert-to-arbitrary-fp.ll
new file mode 100644
index 0000000000000..84d754e2d28dc
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/convert-to-arbitrary-fp.ll
@@ -0,0 +1,826 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc -mtriple=riscv64 -mattr=+b,+f < %s | FileCheck %s
+
+define i8 @bf16_fp8e5m2_nearest(bfloat %x) {
+; CHECK-LABEL: bf16_fp8e5m2_nearest:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    addi sp, sp, -32
+; CHECK-NEXT:    .cfi_def_cfa_offset 32
+; CHECK-NEXT:    sd ra, 24(sp) # 8-byte Folded Spill
+; CHECK-NEXT:    fsw fs0, 20(sp) # 4-byte Folded Spill
+; CHECK-NEXT:    .cfi_offset ra, -8
+; CHECK-NEXT:    .cfi_offset fs0, -12
+; CHECK-NEXT:    fmv.x.w a0, fa0
+; CHECK-NEXT:    slli a0, a0, 16
+; CHECK-NEXT:    fmv.w.x fs0, a0
+; CHECK-NEXT:    mv a0, sp
+; CHECK-NEXT:    fmv.s fa0, fs0
+; CHECK-NEXT:    call frexpf
+; CHECK-NEXT:    fsw fa0, 12(sp)
+; CHECK-NEXT:    fsw fs0, 16(sp)
+; CHECK-NEXT:    lwu a0, 12(sp)
+; CHECK-NEXT:    ld a4, 0(sp)
+; CHECK-NEXT:    slli a3, a0, 41
+; CHECK-NEXT:    srli a3, a3, 41
+; CHECK-NEXT:    slli a1, a0, 44
+; CHECK-NEXT:    snez a1, a1
+; CHECK-NEXT:    bexti a2, a3, 21
+; CHECK-NEXT:    or a1, a1, a2
+; CHECK-NEXT:    srli a0, a0, 20
+; CHECK-NEXT:    and a0, a0, a1
+; CHECK-NEXT:    srli a1, a3, 21
+; CHECK-NEXT:    add a2, a1, a0
+; CHECK-NEXT:    lbu a1, 19(sp)
+; CHECK-NEXT:    slti a0, a2, 4
+; CHECK-NEXT:    xori a5, a0, 1
+; CHECK-NEXT:    add a5, a4, a5
+; CHECK-NEXT:    neg a6, a0
+; CHECK-NEXT:    addi a0, a5, 14
+; CHECK-NEXT:    andi a1, a1, 128
+; CHECK-NEXT:    and a2, a6, a2
+; CHECK-NEXT:    blez a0, .LBB0_2
+; CHECK-NEXT:  # %bb.1:
+; CHECK-NEXT:    slli a3, a0, 2
+; CHECK-NEXT:    or a4, a1, a2
+; CHECK-NEXT:    or a3, a4, a3
+; CHECK-NEXT:    j .LBB0_3
+; CHECK-NEXT:  .LBB0_2:
+; CHECK-NEXT:    li a5, 8
+; CHECK-NEXT:    li a6, 31
+; CHECK-NEXT:    sub a5, a5, a4
+; CHECK-NEXT:    li a4, 1
+; CHECK-NEXT:    minu a5, a5, a6
+; CHECK-NEXT:    maxu a4, a5, a4
+; CHECK-NEXT:    addi a4, a4, -1
+; CHECK-NEXT:    bset a6, zero, a4
+; CHECK-NEXT:    bseti a3, a3, 23
+; CHECK-NEXT:    addi a6, a6, -1
+; CHECK-NEXT:    and a6, a3, a6
+; CHECK-NEXT:    bext a7, a3, a5
+; CHECK-NEXT:    snez a6, a6
+; CHECK-NEXT:    or a6, a6, a7
+; CHECK-NEXT:    srl a4, a3, a4
+; CHECK-NEXT:    seqz a7, a5
+; CHECK-NEXT:    and a4, a4, a6
+; CHECK-NEXT:    addi a7, a7, -1
+; CHECK-NEXT:    and a4, a7, a4
+; CHECK-NEXT:    srl a3, a3, a5
+; CHECK-NEXT:    add a3, a3, a4
+; CHECK-NEXT:    slti a4, a3, 4
+; CHECK-NEXT:    xori a5, a4, 1
+; CHECK-NEXT:    neg a4, a4
+; CHECK-NEXT:    sh2add a5, a5, a1
+; CHECK-NEXT:    and a3, a4, a3
+; CHECK-NEXT:    or a3, a5, a3
+; CHECK-NEXT:  .LBB0_3:
+; CHECK-NEXT:    slti a2, a2, 4
+; CHECK-NEXT:    addi a4, a0, -30
+; CHECK-NEXT:    xori a2, a2, 1
+; CHECK-NEXT:    seqz a4, a4
+; CHECK-NEXT:    slti a0, a0, 31
+; CHECK-NEXT:    and a2, a4, a2
+; CHECK-NEXT:    xori a0, a0, 1
+; CHECK-NEXT:    or a4, a0, a2
+; CHECK-NEXT:    addiw a0, a1, 124
+; CHECK-NEXT:    mv a2, a0
+; CHECK-NEXT:    bnez a4, .LBB0_5
+; CHECK-NEXT:  # %bb.4:
+; CHECK-NEXT:    mv a2, a3
+; CHECK-NEXT:  .LBB0_5:
+; CHECK-NEXT:    fmv.w.x fa5, zero
+; CHECK-NEXT:    feq.s a3, fs0, fa5
+; CHECK-NEXT:    bnez a3, .LBB0_7
+; CHECK-NEXT:  # %bb.6:
+; CHECK-NEXT:    mv a1, a2
+; CHECK-NEXT:  .LBB0_7:
+; CHECK-NEXT:    lui a2, 522240
+; CHECK-NEXT:    fabs.s fa5, fs0
+; CHECK-NEXT:    fmv.w.x fa4, a2
+; CHECK-NEXT:    feq.s a2, fa5, fa4
+; CHECK-NEXT:    bnez a2, .LBB0_9
+; CHECK-NEXT:  # %bb.8:
+; CHECK-NEXT:    mv a0, a1
+; CHECK-NEXT:  .LBB0_9:
+; CHECK-NEXT:    feq.s a1, fs0, fs0
+; CHECK-NEXT:    bnez a1, .LBB0_11
+; CHECK-NEXT:  # %bb.10:
+; CHECK-NEXT:    li a0, 126
+; CHECK-NEXT:  .LBB0_11:
+; CHECK-NEXT:    ld ra, 24(sp) # 8-byte Folded Reload
+; CHECK-NEXT:    flw fs0, 20(sp) # 4-byte Folded Reload
+; CHECK-NEXT:    .cfi_restore ra
+; CHECK-NEXT:    .cfi_restore fs0
+; CHECK-NEXT:    addi sp, sp, 32
+; CHECK-NEXT:    .cfi_def_cfa_offset 0
+; CHECK-NEXT:    ret
+  %r = call i8 @llvm.convert.to.arbitrary.fp(bfloat %x, metadata !"Float8E5M2", metadata !"round.tonearest", i1 false)
+  ret i8 %r
+}
+
+define i8 @bf16_fp8e5m2_toward_zero(bfloat %x) {
+; CHECK-LABEL: bf16_fp8e5m2_toward_zero:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    addi sp, sp, -32
+; CHECK-NEXT:    .cfi_def_cfa_offset 32
+; CHECK-NEXT:    sd ra, 24(sp) # 8-byte Folded Spill
+; CHECK-NEXT:    fsw fs0, 20(sp) # 4-byte Folded Spill
+; CHECK-NEXT:    .cfi_offset ra, -8
+; CHECK-NEXT:    .cfi_offset fs0, -12
+; CHECK-NEXT:    fmv.x.w a0, fa0
+; CHECK-NEXT:    slli a0, a0, 16
+; CHECK-NEXT:    fmv.w.x fs0, a0
+; CHECK-NEXT:    mv a0, sp
+; CHECK-NEXT:    fmv.s fa0, fs0
+; CHECK-NEXT:    call frexpf
+; CHECK-NEXT:    fsw fa0, 12(sp)
+; CHECK-NEXT:    fsw fs0, 16(sp)
+; CHECK-NEXT:    lw a0, 12(sp)
+; CHECK-NEXT:    slli a0, a0, 41
+; CHECK-NEXT:    ld a4, 0(sp)
+; CHECK-NEXT:    srli a3, a0, 41
+; CHECK-NEXT:    srli a2, a3, 21
+; CHECK-NEXT:    lbu a1, 19(sp)
+; CHECK-NEXT:    slti a0, a2, 4
+; CHECK-NEXT:    xori a5, a0, 1
+; CHECK-NEXT:    add a5, a4, a5
+; CHECK-NEXT:    neg a6, a0
+; CHECK-NEXT:    addi a0, a5, 14
+; CHECK-NEXT:    andi a1, a1, 128
+; CHECK-NEXT:    and a2, a6, a2
+; CHECK-NEXT:    blez a0, .LBB1_2
+; CHECK-NEXT:  # %bb.1:
+; CHECK-NEXT:    slli a3, a0, 2
+; CHECK-NEXT:    or a4, a1, a2
+; CHECK-NEXT:    or a3, a4, a3
+; CHECK-NEXT:    j .LBB1_3
+; CHECK-NEXT:  .LBB1_2:
+; CHECK-NEXT:    li a5, 8
+; CHECK-NEXT:    sub a5, a5, a4
+; CHECK-NEXT:    li a4, 31
+; CHECK-NEXT:    minu a4, a5, a4
+; CHECK-NEXT:    bseti a3, a3, 23
+; CHECK-NEXT:    srl a3, a3, a4
+; CHECK-NEXT:    slti a4, a3, 4
+; CHECK-NEXT:    xori a5, a4, 1
+; CHECK-NEXT:    neg a4, a4
+; CHECK-NEXT:    sh2add a5, a5, a1
+; CHECK-NEXT:    and a3, a4, a3
+; CHECK-NEXT:    or a3, a5, a3
+; CHECK-NEXT:  .LBB1_3:
+; CHECK-NEXT:    slti a2, a2, 4
+; CHECK-NEXT:    addi a4, a0, -30
+; CHECK-NEXT:    xori a2, a2, 1
+; CHECK-NEXT:    seqz a4, a4
+; CHECK-NEXT:    slti a0, a0, 31
+; CHECK-NEXT:    and a2, a4, a2
+; CHECK-NEXT:    xori a0, a0, 1
+; CHECK-NEXT:    or a4, a0, a2
+; CHECK-NEXT:    addiw a0, a1, 124
+; CHECK-NEXT:    mv a2, a0
+; CHECK-NEXT:    bnez a4, .LBB1_5
+; CHECK-NEXT:  # %bb.4:
+; CHECK-NEXT:    mv a2, a3
+; CHECK-NEXT:  .LBB1_5:
+; CHECK-NEXT:    fmv.w.x fa5, zero
+; CHECK-NEXT:    feq.s a3, fs0, fa5
+; CHECK-NEXT:    bnez a3, .LBB1_7
+; CHECK-NEXT:  # %bb.6:
+; CHECK-NEXT:    mv a1, a2
+; CHECK-NEXT:  .LBB1_7:
+; CHECK-NEXT:    lui a2, 522240
+; CHECK-NEXT:    fabs.s fa5, fs0
+; CHECK-NEXT:    fmv.w.x fa4, a2
+; CHECK-NEXT:    feq.s a2, fa5, fa4
+; CHECK-NEXT:    bnez a2, .LBB1_9
+; CHECK-NEXT:  # %bb.8:
+; CHECK-NEXT:    mv a0, a1
+; CHECK-NEXT:  .LBB1_9:
+; CHECK-NEXT:    feq.s a1, fs0, fs0
+; CHECK-NEXT:    bnez a1, .LBB1_11
+; CHECK-NEXT:  # %bb.10:
+; CHECK-NEXT:    li a0, 126
+; CHECK-NEXT:  .LBB1_11:
+; CHECK-NEXT:    ld ra, 24(sp) # 8-byte Folded Reload
+; CHECK-NEXT:    flw fs0, 20(sp) # 4-byte Folded Reload
+; CHECK-NEXT:    .cfi_restore ra
+; CHECK-NEXT:    .cfi_restore fs0
+; CHECK-NEXT:    addi sp, sp, 32
+; CHECK-NEXT:    .cfi_def_cfa_offset 0
+; CHECK-NEXT:    ret
+  %r = call i8 @llvm.convert.to.arbitrary.fp(bfloat %x, metadata !"Float8E5M2", metadata !"round.towardzero", i1 false)
+  ret i8 %r
+}
+
+define i8 @bf16_fp8e5m2_nearest_sat(bfloat %x) {
+; CHECK-LABEL: bf16_fp8e5m2_nearest_sat:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    addi sp, sp, -32
+; CHECK-NEXT:    .cfi_def_cfa_offset 32
+; CHECK-NEXT:    sd ra, 24(sp) # 8-byte Folded Spill
+; CHECK-NEXT:    fsw fs0, 20(sp) # 4-byte Folded Spill
+; CHECK-NEXT:    .cfi_offset ra, -8
+; CHECK-NEXT:    .cfi_offset fs0, -12
+; CHECK-NEXT:    fmv.x.w a0, fa0
+; CHECK-NEXT:    slli a0, a0, 16
+; CHECK-NEXT:    fmv.w.x fs0, a0
+; CHECK-NEXT:    mv a0, sp
+; CHECK-NEXT:    fmv.s fa0, fs0
+; CHECK-NEXT:    call frexpf
+; CHECK-NEXT:    fsw fa0, 12(sp)
+; CHECK-NEXT:    fsw fs0, 16(sp)
+; CHECK-NEXT:    lwu a0, 12(sp)
+; CHECK-NEXT:    ld a4, 0(sp)
+; CHECK-NEXT:    slli a3, a0, 41
+; CHECK-NEXT:    srli a3, a3, 41
+; CHECK-NEXT:    slli a1, a0, 44
+; CHECK-NEXT:    snez a1, a1
+; CHECK-NEXT:    bexti a2, a3, 21
+; CHECK-NEXT:    or a1, a1, a2
+; CHECK-NEXT:    srli a0, a0, 20
+; CHECK-NEXT:    and a0, a0, a1
+; CHECK-NEXT:    srli a1, a3, 21
+; CHECK-NEXT:    add a2, a1, a0
+; CHECK-NEXT:    lbu a1, 19(sp)
+; CHECK-NEXT:    slti a0, a2, 4
+; CHECK-NEXT:    xori a5, a0, 1
+; CHECK-NEXT:    add a5, a4, a5
+; CHECK-NEXT:    neg a6, a0
+; CHECK-NEXT:    addi a0, a5, 14
+; CHECK-NEXT:    andi a1, a1, 128
+; CHECK-NEXT:    and a2, a6, a2
+; CHECK-NEXT:    blez a0, .LBB2_2
+; CHECK-NEXT:  # %bb.1:
+; CHECK-NEXT:    slli a3, a0, 2
+; CHECK-NEXT:    or a4, a1, a2
+; CHECK-NEXT:    or a3, a4, a3
+; CHECK-NEXT:    j .LBB2_3
+; CHECK-NEXT:  .LBB2_2:
+; CHECK-NEXT:    li a5, 8
+; CHECK-NEXT:    li a6, 31
+; CHECK-NEXT:    sub a5, a5, a4
+; CHECK-NEXT:    li a4, 1
+; CHECK-NEXT:    minu a5, a5, a6
+; CHECK-NEXT:    maxu a4, a5, a4
+; CHECK-NEXT:    addi a4, a4, -1
+; CHECK-NEXT:    bset a6, zero, a4
+; CHECK-NEXT:    bseti a3, a3, 23
+; CHECK-NEXT:    addi a6, a6, -1
+; CHECK-NEXT:    and a6, a3, a6
+; CHECK-NEXT:    bext a7, a3, a5
+; CHECK-NEXT:    snez a6, a6
+; CHECK-NEXT:    or a6, a6, a7
+; CHECK-NEXT:    srl a4, a3, a4
+; CHECK-NEXT:    seqz a7, a5
+; CHECK-NEXT:    and a4, a4, a6
+; CHECK-NEXT:    addi a7, a7, -1
+; CHECK-NEXT:    and a4, a7, a4
+; CHECK-NEXT:    srl a3, a3, a5
+; CHECK-NEXT:    add a3, a3, a4
+; CHECK-NEXT:    slti a4, a3, 4
+; CHECK-NEXT:    xori a5, a4, 1
+; CHECK-NEXT:    neg a4, a4
+; CHECK-NEXT:    sh2add a5, a5, a1
+; CHECK-NEXT:    and a3, a4, a3
+; CHECK-NEXT:    or a3, a5, a3
+; CHECK-NEXT:  .LBB2_3:
+; CHECK-NEXT:    slti a2, a2, 4
+; CHECK-NEXT:    addi a4, a0, -30
+; CHECK-NEXT:    xori a2, a2, 1
+; CHECK-NEXT:    seqz a4, a4
+; CHECK-NEXT:    slti a0, a0, 31
+; CHECK-NEXT:    and a2, a4, a2
+; CHECK-NEXT:    xori a0, a0, 1
+; CHECK-NEXT:    or a0, a0, a2
+; CHECK-NEXT:    beqz a0, .LBB2_5
+; CHECK-NEXT:  # %bb.4:
+; CHECK-NEXT:    addiw a3, a1, 123
+; CHECK-NEXT:  .LBB2_5:
+; CHECK-NEXT:    fmv.w.x fa5, zero
+; CHECK-NEXT:    feq.s a2, fs0, fa5
+; CHECK-NEXT:    mv a0, a1
+; CHECK-NEXT:    bnez a2, .LBB2_7
+; CHECK-NEXT:  # %bb.6:
+; CHECK-NEXT:    mv a0, a3
+; CHECK-NEXT:  .LBB2_7:
+; CHECK-NEXT:    lui a2, 522240
+; CHECK-NEXT:    fabs.s fa5, fs0
+; CHECK-NEXT:    fmv.w.x fa4, a2
+; CHECK-NEXT:    feq.s a2, fa5, fa4
+; CHECK-NEXT:    beqz a2, .LBB2_9
+; CHECK-NEXT:  # %bb.8:
+; CHECK-NEXT:    addiw a0, a1, 124
+; CHECK-NEXT:  .LBB2_9:
+; CHECK-NEXT:    feq.s a1, fs0, fs0
+; CHECK-NEXT:    bnez a1, .LBB2_11
+; CHECK-NEXT:  # %bb.10:
+; CHECK-NEXT:    li a0, 126
+; CHECK-NEXT:  .LBB2_11:
+; CHECK-NEXT:    ld ra, 24(sp) # 8-byte Folded Reload
+; CHECK-NEXT:    flw fs0, 20(sp) # 4-byte Folded Reload
+; CHECK-NEXT:    .cfi_restore ra
+; CHECK-NEXT:    .cfi_restore fs0
+; CHECK-NEXT:    addi sp, sp, 32
+; CHECK-NEXT:    .cfi_def_cfa_offset 0
+; CHECK-NEXT:    ret
+  %r = call i8 @llvm.convert.to.arbitrary.fp(bfloat %x, metadata !"Float8E5M2", metadata !"round.tonearest", i1 true)
+  ret i8 %r
+}
+
+define i8 @bf16_fp8e5m2_toward_zero_sat(bfloat %x) {
+; CHECK-LABEL: bf16_fp8e5m2_toward_zero_sat:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    addi sp, sp, -32
+; CHECK-NEXT:    .cfi_def_cfa_offset 32
+; CHECK-NEXT:    sd ra, 24(sp) # 8-byte Folded Spill
+; CHECK-NEXT:    fsw fs0, 20(sp) # 4-byte Folded Spill
+; CHECK-NEXT:    .cfi_offset ra, -8
+; CHECK-NEXT:    .cfi_offset fs0, -12
+; CHECK-NEXT:    fmv.x.w a0, fa0
+; CHECK-NEXT:    slli a0, a0, 16
+; CHECK-NEXT:    fmv.w.x fs0, a0
+; CHECK-NEXT:    mv a0, sp
+; CHECK-NEXT:    fmv.s fa0, fs0
+; CHECK-NEXT:    call frexpf
+; CHECK-NEXT:    fsw fa0, 12(sp)
+; CHECK-NEXT:    fsw fs0, 16(sp)
+; CHECK-NEXT:    lw a0, 12(sp)
+; CHECK-NEXT:    slli a0, a0, 41
+; CHECK-NEXT:    ld a4, 0(sp)
+; CHECK-NEXT:    srli a2, a0, 41
+; CHECK-NEXT:    srli a3, a2, 21
+; CHECK-NEXT:    lbu a1, 19(sp)
+; CHECK-NEXT:    slti a0, a3, 4
+; CHECK-NEXT:    xori a5, a0, 1
+; CHECK-NEXT:    add a5, a4, a5
+; CHECK-NEXT:    neg a6, a0
+; CHECK-NEXT:    addi a0, a5, 14
+; CHECK-NEXT:    andi a1, a1, 128
+; CHECK-NEXT:    and a3, a6, a3
+; CHECK-NEXT:    blez a0, .LBB3_2
+; CHECK-NEXT:  # %bb.1:
+; CHECK-NEXT:    slli a2, a0, 2
+; CHECK-NEXT:    or a4, a1, a3
+; CHECK-NEXT:    or a2, a4, a2
+; CHECK-NEXT:    j .LBB3_3
+; CHECK-NEXT:  .LBB3_2:
+; CHECK-NEXT:    li a5, 8
+; CHECK-NEXT:    sub a5, a5, a4
+; CHECK-NEXT:    li a4, 31
+; CHECK-NEXT:    minu a4, a5, a4
+; CHECK-NEXT:    bseti a2, a2, 23
+; CHECK-NEXT:    srl a2, a2, a4
+; CHECK-NEXT:    slti a4, a2, 4
+; CHECK-NEXT:    xori a5, a4, 1
+; CHECK-NEXT:    neg a4, a4
+; CHECK-NEXT:    sh2add a5, a5, a1
+; CHECK-NEXT:    and a2, a4, a2
+; CHECK-NEXT:    or a2, a5, a2
+; CHECK-NEXT:  .LBB3_3:
+; CHECK-NEXT:    slti a3, a3, 4
+; CHECK-NEXT:    addi a4, a0, -30
+; CHECK-NEXT:    xori a3, a3, 1
+; CHECK-NEXT:    seqz a4, a4
+; CHECK-NEXT:    slti a0, a0, 31
+; CHECK-NEXT:    and a3, a4, a3
+; CHECK-NEXT:    xori a0, a0, 1
+; CHECK-NEXT:    or a0, a0, a3
+; CHECK-NEXT:    beqz a0, .LBB3_5
+; CHECK-NEXT:  # %bb.4:
+; CHECK-NEXT:    addiw a2, a1, 123
+; CHECK-NEXT:  .LBB3_5:
+; CHECK-NEXT:    fmv.w.x fa5, zero
+; CHECK-NEXT:    feq.s a3, fs0, fa5
+; CHECK-NEXT:    mv a0, a1
+; CHECK-NEXT:    bnez a3, .LBB3_7
+; CHECK-NEXT:  # %bb.6:
+; CHECK-NEXT:    mv a0, a2
+; CHECK-NEXT:  .LBB3_7:
+; CHECK-NEXT:    lui a2, 522240
+; CHECK-NEXT:    fabs.s fa5, fs0
+; CHECK-NEXT:    fmv.w.x fa4, a2
+; CHECK-NEXT:    feq.s a2, fa5, fa4
+; CHECK-NEXT:    beqz a2, .LBB3_9
+; CHECK-NEXT:  # %bb.8:
+; CHECK-NEXT:    addiw a0, a1, 124
+; CHECK-NEXT:  .LBB3_9:
+; CHECK-NEXT:    feq.s a1, fs0, fs0
+; CHECK-NEXT:    bnez a1, .LBB3_11
+; CHECK-NEXT:  # %bb.10:
+; CHECK-NEXT:    li a0, 126
+; CHECK-NEXT:  .LBB3_11:
+; CHECK-NEXT:    ld ra, 24(sp) # 8-byte Folded Reload
+; CHECK-NEXT:    flw fs0, 20(sp) # 4-byte Folded Reload
+; CHECK-NEXT:    .cfi_restore ra
+; CHECK-NEXT:    .cfi_restore fs0
+; CHECK-NEXT:    addi sp, sp, 32
+; CHECK-NEXT:    .cfi_def_cfa_offset 0
+; CHECK-NEXT:    ret
+  %r = call i8 @llvm.convert.to.arbitrary.fp(bfloat %x, metadata !"Float8E5M2", metadata !"round.towardzero", i1 true)
+  ret i8 %r
+}
+
+define i8 @f32_fp8e5m2_nearest(float %x) {
+; CHECK-LABEL: f32_fp8e5m2_nearest:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    addi sp, sp, -32
+; CHECK-NEXT:    .cfi_def_cfa_offset 32
+; CHECK-NEXT:    sd ra, 24(sp) # 8-byte Folded Spill
+; CHECK-NEXT:    fsw fs0, 20(sp) # 4-byte Folded Spill
+; CHECK-NEXT:    .cfi_offset ra, -8
+; CHECK-NEXT:    .cfi_offset fs0, -12
+; CHECK-NEXT:    fmv.s fs0, fa0
+; CHECK-NEXT:    mv a0, sp
+; CHECK-NEXT:    call frexpf
+; CHECK-NEXT:    fsw fa0, 12(sp)
+; CHECK-NEXT:    fsw fs0, 16(sp)
+; CHECK-NEXT:    lwu a0, 12(sp)
+; CHECK-NEXT:    ld a4, 0(sp)
+; CHECK-NEXT:    slli a3, a0, 41
+; CHECK-NEXT:    srli a3, a3, 41
+; CHECK-NEXT:    slli a1, a0, 44
+; CHECK-NEXT:    snez a1, a1
+; CHECK-NEXT:    bexti a2, a3, 21
+; CHECK-NEXT:    or a1, a1, a2
+; CHECK-NEXT:    srli a0, a0, 20
+; CHECK-NEXT:    and a0, a0, a1
+; CHECK-NEXT:    srli a1, a3, 21
+; CHECK-NEXT:    add a2, a1, a0
+; CHECK-NEXT:    lbu a1, 19(sp)
+; CHECK-NEXT:    slti a0, a2, 4
+; CHECK-NEXT:    xori a5, a0, 1
+; CHECK-NEXT:    add a5, a4, a5
+; CHECK-NEXT:    neg a6, a0
+; CHECK-NEXT:    addi a0, a5, 14
+; CHECK-NEXT:    andi a1, a1, 128
+; CHECK-NEXT:    and a2, a6, a2
+; CHECK-NEXT:    blez a0, .LBB4_2
+; CHECK-NEXT:  # %bb.1:
+; CHECK-NEXT:    slli a3, a0, 2
+; CHECK-NEXT:    or a4, a1, a2
+; CHECK-NEXT:    or a3, a4, a3
+; CHECK-NEXT:    j .LBB4_3
+; CHECK-NEXT:  .LBB4_2:
+; CHECK-NEXT:    li a5, 8
+; CHECK-NEXT:    li a6, 31
+; CHECK-NEXT:    sub a5, a5, a4
+; CHECK-NEXT:    li a4, 1
+; CHECK-NEXT:    minu a5, a5, a6
+; CHECK-NEXT:    maxu a4, a5, a4
+; CHECK-NEXT:    addi a4, a4, -1
+; CHECK-NEXT:    bset a6, zero, a4
+; CHECK-NEXT:    bseti a3, a3, 23
+; CHECK-NEXT:    addi a6, a6, -1
+; CHECK-NEXT:    and a6, a3, a6
+; CHECK-NEXT:    bext a7, a3, a5
+; CHECK-NEXT:    snez a6, a6
+; CHECK-NEXT:    or a6, a6, a7
+; CHECK-NEXT:    srl a4, a3, a4
+; CHECK-NEXT:    seqz a7, a5
+; CHECK-NEXT:    and a4, a4, a6
+; CHECK-NEXT:    addi a7, a7, -1
+; CHECK-NEXT:    and a4, a7, a4
+; CHECK-NEXT:    srl a3, a3, a5
+; CHECK-NEXT:    add a3, a3, a4
+; CHECK-NEXT:    slti a4, a3, 4
+; CHECK-NEXT:    xori a5, a4, 1
+; CHECK-NEXT:    neg a4, a4
+; CHECK-NEXT:    sh2add a5, a5, a1
+; CHECK-NEXT:    and a3, a4, a3
+; CHECK-NEXT:    or a3, a5, a3
+; CHECK-NEXT:  .LBB4_3:
+; CHECK-NEXT:    slti a2, a2, 4
+; CHECK-NEXT:    addi a4, a0, -30
+; CHECK-NEXT:    xori a2, a2, 1
+; CHECK-NEXT:    seqz a4, a4
+; CHECK-NEXT:    slti a0, a0, 31
+; CHECK-NEXT:    and a2, a4, a2
+; CHECK-NEXT:    xori a0, a0, 1
+; CHECK-NEXT:    or a4, a0, a2
+; CHECK-NEXT:    addiw a0, a1, 124
+; CHECK-NEXT:    mv a2, a0
+; CHECK-NEXT:    bnez a4, .LBB4_5
+; CHECK-NEXT:  # %bb.4:
+; CHECK-NEXT:    mv a2, a3
+; CHECK-NEXT:  .LBB4_5:
+; CHECK-NEXT:    fmv.w.x fa5, zero
+; CHECK-NEXT:    feq.s a3, fs0, fa5
+; CHECK-NEXT:    bnez a3, .LBB4_7
+; CHECK-NEXT:  # %bb.6:
+; CHECK-NEXT:    mv a1, a2
+; CHECK-NEXT:  .LBB4_7:
+; CHECK-NEXT:    lui a2, 522240
+; CHECK-NEXT:    fabs.s fa5, fs0
+; CHECK-NEXT:    fmv.w.x fa4, a2
+; CHECK-NEXT:    feq.s a2, fa5, fa4
+; CHECK-NEXT:    bnez a2, .LBB4_9
+; CHECK-NEXT:  # %bb.8:
+; CHECK-NEXT:    mv a0, a1
+; CHECK-NEXT:  .LBB4_9:
+; CHECK-NEXT:    feq.s a1, fs0, fs0
+; CHECK-NEXT:    bnez a1, .LBB4_11
+; CHECK-NEXT:  # %bb.10:
+; CHECK-NEXT:    li a0, 126
+; CHECK-NEXT:  .LBB4_11:
+; CHECK-NEXT:    ld ra, 24(sp) # 8-byte Folded Reload
+; CHECK-NEXT:    flw fs0, 20(sp) # 4-byte Folded Reload
+; CHECK-NEXT:    .cfi_restore ra
+; CHECK-NEXT:    .cfi_restore fs0
+; CHECK-NEXT:    addi sp, sp, 32
+; CHECK-NEXT:    .cfi_def_cfa_offset 0
+; CHECK-NEXT:    ret
+  %r = call i8 @llvm.convert.to.arbitrary.fp(float %x, metadata !"Float8E5M2", metadata !"round.tonearest", i1 false)
+  ret i8 %r
+}
+
+define i8 @f32_fp8e5m2_toward_zero(float %x) {
+; CHECK-LABEL: f32_fp8e5m2_toward_zero:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    addi sp, sp, -32
+; CHECK-NEXT:    .cfi_def_cfa_offset 32
+; CHECK-NEXT:    sd ra, 24(sp) # 8-byte Folded Spill
+; CHECK-NEXT:    fsw fs0, 20(sp) # 4-byte Folded Spill
+; CHECK-NEXT:    .cfi_offset ra, -8
+; CHECK-NEXT:    .cfi_offset fs0, -12
+; CHECK-NEXT:    fmv.s fs0, fa0
+; CHECK-NEXT:    mv a0, sp
+; CHECK-NEXT:    call frexpf
+; CHECK-NEXT:    fsw fa0, 12(sp)
+; CHECK-NEXT:    fsw fs0, 16(sp)
+; CHECK-NEXT:    lw a0, 12(sp)
+; CHECK-NEXT:    slli a0, a0, 41
+; CHECK-NEXT:    ld a4, 0(sp)
+; CHECK-NEXT:    srli a3, a0, 41
+; CHECK-NEXT:    srli a2, a3, 21
+; CHECK-NEXT:    lbu a1, 19(sp)
+; CHECK-NEXT:    slti a0, a2, 4
+; CHECK-NEXT:    xori a5, a0, 1
+; CHECK-NEXT:    add a5, a4, a5
+; CHECK-NEXT:    neg a6, a0
+; CHECK-NEXT:    addi a0, a5, 14
+; CHECK-NEXT:    andi a1, a1, 128
+; CHECK-NEXT:    and a2, a6, a2
+; CHECK-NEXT:    blez a0, .LBB5_2
+; CHECK-NEXT:  # %bb.1:
+; CHECK-NEXT:    slli a3, a0, 2
+; CHECK-NEXT:    or a4, a1, a2
+; CHECK-NEXT:    or a3, a4, a3
+; CHECK-NEXT:    j .LBB5_3
+; CHECK-NEXT:  .LBB5_2:
+; CHECK-NEXT:    li a5, 8
+; CHECK-NEXT:    sub a5, a5, a4
+; CHECK-NEXT:    li a4, 31
+; CHECK-NEXT:    minu a4, a5, a4
+; CHECK-NEXT:    bseti a3, a3, 23
+; CHECK-NEXT:    srl a3, a3, a4
+; CHECK-NEXT:    slti a4, a3, 4
+; CHECK-NEXT:    xori a5, a4, 1
+; CHECK-NEXT:    neg a4, a4
+; CHECK-NEXT:    sh2add a5, a5, a1
+; CHECK-NEXT:    and a3, a4, a3
+; CHECK-NEXT:    or a3, a5, a3
+; CHECK-NEXT:  .LBB5_3:
+; CHECK-NEXT:    slti a2, a2, 4
+; CHECK-NEXT:    addi a4, a0, -30
+; CHECK-NEXT:    xori a2, a2, 1
+; CHECK-NEXT:    seqz a4, a4
+; CHECK-NEXT:    slti a0, a0, 31
+; CHECK-NEXT:    and a2, a4, a2
+; CHECK-NEXT:    xori a0, a0, 1
+; CHECK-NEXT:    or a4, a0, a2
+; CHECK-NEXT:    addiw a0, a1, 124
+; CHECK-NEXT:    mv a2, a0
+; CHECK-NEXT:    bnez a4, .LBB5_5
+; CHECK-NEXT:  # %bb.4:
+; CHECK-NEXT:    mv a2, a3
+; CHECK-NEXT:  .LBB5_5:
+; CHECK-NEXT:    fmv.w.x fa5, zero
+; CHECK-NEXT:    feq.s a3, fs0, fa5
+; CHECK-NEXT:    bnez a3, .LBB5_7
+; CHECK-NEXT:  # %bb.6:
+; CHECK-NEXT:    mv a1, a2
+; CHECK-NEXT:  .LBB5_7:
+; CHECK-NEXT:    lui a2, 522240
+; CHECK-NEXT:    fabs.s fa5, fs0
+; CHECK-NEXT:    fmv.w.x fa4, a2
+; CHECK-NEXT:    feq.s a2, fa5, fa4
+; CHECK-NEXT:    bnez a2, .LBB5_9
+; CHECK-NEXT:  # %bb.8:
+; CHECK-NEXT:    mv a0, a1
+; CHECK-NEXT:  .LBB5_9:
+; CHECK-NEXT:    feq.s a1, fs0, fs0
+; CHECK-NEXT:    bnez a1, .LBB5_11
+; CHECK-NEXT:  # %bb.10:
+; CHECK-NEXT:    li a0, 126
+; CHECK-NEXT:  .LBB5_11:
+; CHECK-NEXT:    ld ra, 24(sp) # 8-byte Folded Reload
+; CHECK-NEXT:    flw fs0, 20(sp) # 4-byte Folded Reload
+; CHECK-NEXT:    .cfi_restore ra
+; CHECK-NEXT:    .cfi_restore fs0
+; CHECK-NEXT:    addi sp, sp, 32
+; CHECK-NEXT:    .cfi_def_cfa_offset 0
+; CHECK-NEXT:    ret
+  %r = call i8 @llvm.convert.to.arbitrary.fp(float %x, metadata !"Float8E5M2", metadata !"round.towardzero", i1 false)
+  ret i8 %r
+}
+
+define i8 @f32_fp8e5m2_nearest_sat(float %x) {
+; CHECK-LABEL: f32_fp8e5m2_nearest_sat:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    addi sp, sp, -32
+; CHECK-NEXT:    .cfi_def_cfa_offset 32
+; CHECK-NEXT:    sd ra, 24(sp) # 8-byte Folded Spill
+; CHECK-NEXT:    fsw fs0, 20(sp) # 4-byte Folded Spill
+; CHECK-NEXT:    .cfi_offset ra, -8
+; CHECK-NEXT:    .cfi_offset fs0, -12
+; CHECK-NEXT:    fmv.s fs0, fa0
+; CHECK-NEXT:    mv a0, sp
+; CHECK-NEXT:    call frexpf
+; CHECK-NEXT:    fsw fa0, 12(sp)
+; CHECK-NEXT:    fsw fs0, 16(sp)
+; CHECK-NEXT:    lwu a0, 12(sp)
+; CHECK-NEXT:    ld a4, 0(sp)
+; CHECK-NEXT:    slli a3, a0, 41
+; CHECK-NEXT:    srli a3, a3, 41
+; CHECK-NEXT:    slli a1, a0, 44
+; CHECK-NEXT:    snez a1, a1
+; CHECK-NEXT:    bexti a2, a3, 21
+; CHECK-NEXT:    or a1, a1, a2
+; CHECK-NEXT:    srli a0, a0, 20
+; CHECK-NEXT:    and a0, a0, a1
+; CHECK-NEXT:    srli a1, a3, 21
+; CHECK-NEXT:    add a2, a1, a0
+; CHECK-NEXT:    lbu a1, 19(sp)
+; CHECK-NEXT:    slti a0, a2, 4
+; CHECK-NEXT:    xori a5, a0, 1
+; CHECK-NEXT:    add a5, a4, a5
+; CHECK-NEXT:    neg a6, a0
+; CHECK-NEXT:    addi a0, a5, 14
+; CHECK-NEXT:    andi a1, a1, 128
+; CHECK-NEXT:    and a2, a6, a2
+; CHECK-NEXT:    blez a0, .LBB6_2
+; CHECK-NEXT:  # %bb.1:
+; CHECK-NEXT:    slli a3, a0, 2
+; CHECK-NEXT:    or a4, a1, a2
+; CHECK-NEXT:    or a3, a4, a3
+; CHECK-NEXT:    j .LBB6_3
+; CHECK-NEXT:  .LBB6_2:
+; CHECK-NEXT:    li a5, 8
+; CHECK-NEXT:    li a6, 31
+; CHECK-NEXT:    sub a5, a5, a4
+; CHECK-NEXT:    li a4, 1
+; CHECK-NEXT:    minu a5, a5, a6
+; CHECK-NEXT:    maxu a4, a5, a4
+; CHECK-NEXT:    addi a4, a4, -1
+; CHECK-NEXT:    bset a6, zero, a4
+; CHECK-NEXT:    bseti a3, a3, 23
+; CHECK-NEXT:    addi a6, a6, -1
+; CHECK-NEXT:    and a6, a3, a6
+; CHECK-NEXT:    bext a7, a3, a5
+; CHECK-NEXT:    snez a6, a6
+; CHECK-NEXT:    or a6, a6, a7
+; CHECK-NEXT:    srl a4, a3, a4
+; CHECK-NEXT:    seqz a7, a5
+; CHECK-NEXT:    and a4, a4, a6
+; CHECK-NEXT:    addi a7, a7, -1
+; CHECK-NEXT:    and a4, a7, a4
+; CHECK-NEXT:    srl a3, a3, a5
+; CHECK-NEXT:    add a3, a3, a4
+; CHECK-NEXT:    slti a4, a3, 4
+; CHECK-NEXT:    xori a5, a4, 1
+; CHECK-NEXT:    neg a4, a4
+; CHECK-NEXT:    sh2add a5, a5, a1
+; CHECK-NEXT:    and a3, a4, a3
+; CHECK-NEXT:    or a3, a5, a3
+; CHECK-NEXT:  .LBB6_3:
+; CHECK-NEXT:    slti a2, a2, 4
+; CHECK-NEXT:    addi a4, a0, -30
+; CHECK-NEXT:    xori a2, a2, 1
+; CHECK-NEXT:    seqz a4, a4
+; CHECK-NEXT:    slti a0, a0, 31
+; CHECK-NEXT:    and a2, a4, a2
+; CHECK-NEXT:    xori a0, a0, 1
+; CHECK-NEXT:    or a0, a0, a2
+; CHECK-NEXT:    beqz a0, .LBB6_5
+; CHECK-NEXT:  # %bb.4:
+; CHECK-NEXT:    addiw a3, a1, 123
+; CHECK-NEXT:  .LBB6_5:
+; CHECK-NEXT:    fmv.w.x fa5, zero
+; CHECK-NEXT:    feq.s a2, fs0, fa5
+; CHECK-NEXT:    mv a0, a1
+; CHECK-NEXT:    bnez a2, .LBB6_7
+; CHECK-NEXT:  # %bb.6:
+; CHECK-NEXT:    mv a0, a3
+; CHECK-NEXT:  .LBB6_7:
+; CHECK-NEXT:    lui a2, 522240
+; CHECK-NEXT:    fabs.s fa5, fs0
+; CHECK-NEXT:    fmv.w.x fa4, a2
+; CHECK-NEXT:    feq.s a2, fa5, fa4
+; CHECK-NEXT:    beqz a2, .LBB6_9
+; CHECK-NEXT:  # %bb.8:
+; CHECK-NEXT:    addiw a0, a1, 124
+; CHECK-NEXT:  .LBB6_9:
+; CHECK-NEXT:    feq.s a1, fs0, fs0
+; CHECK-NEXT:    bnez a1, .LBB6_11
+; CHECK-NEXT:  # %bb.10:
+; CHECK-NEXT:    li a0, 126
+; CHECK-NEXT:  .LBB6_11:
+; CHECK-NEXT:    ld ra, 24(sp) # 8-byte Folded Reload
+; CHECK-NEXT:    flw fs0, 20(sp) # 4-byte Folded Reload
+; CHECK-NEXT:    .cfi_restore ra
+; CHECK-NEXT:    .cfi_restore fs0
+; CHECK-NEXT:    addi sp, sp, 32
+; CHECK-NEXT:    .cfi_def_cfa_offset 0
+; CHECK-NEXT:    ret
+  %r = call i8 @llvm.convert.to.arbitrary.fp(float %x, metadata !"Float8E5M2", metadata !"round.tonearest", i1 true)
+  ret i8 %r
+}
+
+define i8 @f32_fp8e5m2_toward_zero_sat(float %x) {
+; CHECK-LABEL: f32_fp8e5m2_toward_zero_sat:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    addi sp, sp, -32
+; CHECK-NEXT:    .cfi_def_cfa_offset 32
+; CHECK-NEXT:    sd ra, 24(sp) # 8-byte Folded Spill
+; CHECK-NEXT:    fsw fs0, 20(sp) # 4-byte Folded Spill
+; CHECK-NEXT:    .cfi_offset ra, -8
+; CHECK-NEXT:    .cfi_offset fs0, -12
+; CHECK-NEXT:    fmv.s fs0, fa0
+; CHECK-NEXT:    mv a0, sp
+; CHECK-NEXT:    call frexpf
+; CHECK-NEXT:    fsw fa0, 12(sp)
+; CHECK-NEXT:    fsw fs0, 16(sp)
+; CHECK-NEXT:    lw a0, 12(sp)
+; CHECK-NEXT:    slli a0, a0, 41
+; CHECK-NEXT:    ld a4, 0(sp)
+; CHECK-NEXT:    srli a2, a0, 41
+; CHECK-NEXT:    srli a3, a2, 21
+; CHECK-NEXT:    lbu a1, 19(sp)
+; CHECK-NEXT:    slti a0, a3, 4
+; CHECK-NEXT:    xori a5, a0, 1
+; CHECK-NEXT:    add a5, a4, a5
+; CHECK-NEXT:    neg a6, a0
+; CHECK-NEXT:    addi a0, a5, 14
+; CHECK-NEXT:    andi a1, a1, 128
+; CHECK-NEXT:    and a3, a6, a3
+; CHECK-NEXT:    blez a0, .LBB7_2
+; CHECK-NEXT:  # %bb.1:
+; CHECK-NEXT:    slli a2, a0, 2
+; CHECK-NEXT:    or a4, a1, a3
+; CHECK-NEXT:    or a2, a4, a2
+; CHECK-NEXT:    j .LBB7_3
+; CHECK-NEXT:  .LBB7_2:
+; CHECK-NEXT:    li a5, 8
+; CHECK-NEXT:    sub a5, a5, a4
+; CHECK-NEXT:    li a4, 31
+; CHECK-NEXT:    minu a4, a5, a4
+; CHECK-NEXT:    bseti a2, a2, 23
+; CHECK-NEXT:    srl a2, a2, a4
+; CHECK-NEXT:    slti a4, a2, 4
+; CHECK-NEXT:    xori a5, a4, 1
+; CHECK-NEXT:    neg a4, a4
+; CHECK-NEXT:    sh2add a5, a5, a1
+; CHECK-NEXT:    and a2, a4, a2
+; CHECK-NEXT:    or a2, a5, a2
+; CHECK-NEXT:  .LBB7_3:
+; CHECK-NEXT:    slti a3, a3, 4
+; CHECK-NEXT:    addi a4, a0, -30
+; CHECK-NEXT:    xori a3, a3, 1
+; CHECK-NEXT:    seqz a4, a4
+; CHECK-NEXT:    slti a0, a0, 31
+; CHECK-NEXT:    and a3, a4, a3
+; CHECK-NEXT:    xori a0, a0, 1
+; CHECK-NEXT:    or a0, a0, a3
+; CHECK-NEXT:    beqz a0, .LBB7_5
+; CHECK-NEXT:  # %bb.4:
+; CHECK-NEXT:    addiw a2, a1, 123
+; CHECK-NEXT:  .LBB7_5:
+; CHECK-NEXT:    fmv.w.x fa5, zero
+; CHECK-NEXT:    feq.s a3, fs0, fa5
+; CHECK-NEXT:    mv a0, a1
+; CHECK-NEXT:    bnez a3, .LBB7_7
+; CHECK-NEXT:  # %bb.6:
+; CHECK-NEXT:    mv a0, a2
+; CHECK-NEXT:  .LBB7_7:
+; CHECK-NEXT:    lui a2, 522240
+; CHECK-NEXT:    fabs.s fa5, fs0
+; CHECK-NEXT:    fmv.w.x fa4, a2
+; CHECK-NEXT:    feq.s a2, fa5, fa4
+; CHECK-NEXT:    beqz a2, .LBB7_9
+; CHECK-NEXT:  # %bb.8:
+; CHECK-NEXT:    addiw a0, a1, 124
+; CHECK-NEXT:  .LBB7_9:
+; CHECK-NEXT:    feq.s a1, fs0, fs0
+; CHECK-NEXT:    bnez a1, .LBB7_11
+; CHECK-NEXT:  # %bb.10:
+; CHECK-NEXT:    li a0, 126
+; CHECK-NEXT:  .LBB7_11:
+; CHECK-NEXT:    ld ra, 24(sp) # 8-byte Folded Reload
+; CHECK-NEXT:    flw fs0, 20(sp) # 4-byte Folded Reload
+; CHECK-NEXT:    .cfi_restore ra
+; CHECK-NEXT:    .cfi_restore fs0
+; CHECK-NEXT:    addi sp, sp, 32
+; CHECK-NEXT:    .cfi_def_cfa_offset 0
+; CHECK-NEXT:    ret
+  %r = call i8 @llvm.convert.to.arbitrary.fp(float %x, metadata !"Float8E5M2", metadata !"round.towardzero", i1 true)
+  ret i8 %r
+}

>From 48efa49666166b65c78687579596474cec6c1a0c Mon Sep 17 00:00:00 2001
From: Min-Yih Hsu <min.hsu at sifive.com>
Date: Fri, 4 Sep 2026 15:25:09 -0700
Subject: [PATCH 2/2] fixup! nounwind

---
 .../CodeGen/RISCV/convert-to-arbitrary-fp.ll  | 64 +++----------------
 1 file changed, 8 insertions(+), 56 deletions(-)

diff --git a/llvm/test/CodeGen/RISCV/convert-to-arbitrary-fp.ll b/llvm/test/CodeGen/RISCV/convert-to-arbitrary-fp.ll
index 84d754e2d28dc..c911556c01bb1 100644
--- a/llvm/test/CodeGen/RISCV/convert-to-arbitrary-fp.ll
+++ b/llvm/test/CodeGen/RISCV/convert-to-arbitrary-fp.ll
@@ -1,15 +1,12 @@
 ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
 ; RUN: llc -mtriple=riscv64 -mattr=+b,+f < %s | FileCheck %s
 
-define i8 @bf16_fp8e5m2_nearest(bfloat %x) {
+define i8 @bf16_fp8e5m2_nearest(bfloat %x) nounwind {
 ; CHECK-LABEL: bf16_fp8e5m2_nearest:
 ; CHECK:       # %bb.0:
 ; CHECK-NEXT:    addi sp, sp, -32
-; CHECK-NEXT:    .cfi_def_cfa_offset 32
 ; CHECK-NEXT:    sd ra, 24(sp) # 8-byte Folded Spill
 ; CHECK-NEXT:    fsw fs0, 20(sp) # 4-byte Folded Spill
-; CHECK-NEXT:    .cfi_offset ra, -8
-; CHECK-NEXT:    .cfi_offset fs0, -12
 ; CHECK-NEXT:    fmv.x.w a0, fa0
 ; CHECK-NEXT:    slli a0, a0, 16
 ; CHECK-NEXT:    fmv.w.x fs0, a0
@@ -108,24 +105,18 @@ define i8 @bf16_fp8e5m2_nearest(bfloat %x) {
 ; CHECK-NEXT:  .LBB0_11:
 ; CHECK-NEXT:    ld ra, 24(sp) # 8-byte Folded Reload
 ; CHECK-NEXT:    flw fs0, 20(sp) # 4-byte Folded Reload
-; CHECK-NEXT:    .cfi_restore ra
-; CHECK-NEXT:    .cfi_restore fs0
 ; CHECK-NEXT:    addi sp, sp, 32
-; CHECK-NEXT:    .cfi_def_cfa_offset 0
 ; CHECK-NEXT:    ret
   %r = call i8 @llvm.convert.to.arbitrary.fp(bfloat %x, metadata !"Float8E5M2", metadata !"round.tonearest", i1 false)
   ret i8 %r
 }
 
-define i8 @bf16_fp8e5m2_toward_zero(bfloat %x) {
+define i8 @bf16_fp8e5m2_toward_zero(bfloat %x) nounwind {
 ; CHECK-LABEL: bf16_fp8e5m2_toward_zero:
 ; CHECK:       # %bb.0:
 ; CHECK-NEXT:    addi sp, sp, -32
-; CHECK-NEXT:    .cfi_def_cfa_offset 32
 ; CHECK-NEXT:    sd ra, 24(sp) # 8-byte Folded Spill
 ; CHECK-NEXT:    fsw fs0, 20(sp) # 4-byte Folded Spill
-; CHECK-NEXT:    .cfi_offset ra, -8
-; CHECK-NEXT:    .cfi_offset fs0, -12
 ; CHECK-NEXT:    fmv.x.w a0, fa0
 ; CHECK-NEXT:    slli a0, a0, 16
 ; CHECK-NEXT:    fmv.w.x fs0, a0
@@ -202,24 +193,18 @@ define i8 @bf16_fp8e5m2_toward_zero(bfloat %x) {
 ; CHECK-NEXT:  .LBB1_11:
 ; CHECK-NEXT:    ld ra, 24(sp) # 8-byte Folded Reload
 ; CHECK-NEXT:    flw fs0, 20(sp) # 4-byte Folded Reload
-; CHECK-NEXT:    .cfi_restore ra
-; CHECK-NEXT:    .cfi_restore fs0
 ; CHECK-NEXT:    addi sp, sp, 32
-; CHECK-NEXT:    .cfi_def_cfa_offset 0
 ; CHECK-NEXT:    ret
   %r = call i8 @llvm.convert.to.arbitrary.fp(bfloat %x, metadata !"Float8E5M2", metadata !"round.towardzero", i1 false)
   ret i8 %r
 }
 
-define i8 @bf16_fp8e5m2_nearest_sat(bfloat %x) {
+define i8 @bf16_fp8e5m2_nearest_sat(bfloat %x) nounwind {
 ; CHECK-LABEL: bf16_fp8e5m2_nearest_sat:
 ; CHECK:       # %bb.0:
 ; CHECK-NEXT:    addi sp, sp, -32
-; CHECK-NEXT:    .cfi_def_cfa_offset 32
 ; CHECK-NEXT:    sd ra, 24(sp) # 8-byte Folded Spill
 ; CHECK-NEXT:    fsw fs0, 20(sp) # 4-byte Folded Spill
-; CHECK-NEXT:    .cfi_offset ra, -8
-; CHECK-NEXT:    .cfi_offset fs0, -12
 ; CHECK-NEXT:    fmv.x.w a0, fa0
 ; CHECK-NEXT:    slli a0, a0, 16
 ; CHECK-NEXT:    fmv.w.x fs0, a0
@@ -317,24 +302,18 @@ define i8 @bf16_fp8e5m2_nearest_sat(bfloat %x) {
 ; CHECK-NEXT:  .LBB2_11:
 ; CHECK-NEXT:    ld ra, 24(sp) # 8-byte Folded Reload
 ; CHECK-NEXT:    flw fs0, 20(sp) # 4-byte Folded Reload
-; CHECK-NEXT:    .cfi_restore ra
-; CHECK-NEXT:    .cfi_restore fs0
 ; CHECK-NEXT:    addi sp, sp, 32
-; CHECK-NEXT:    .cfi_def_cfa_offset 0
 ; CHECK-NEXT:    ret
   %r = call i8 @llvm.convert.to.arbitrary.fp(bfloat %x, metadata !"Float8E5M2", metadata !"round.tonearest", i1 true)
   ret i8 %r
 }
 
-define i8 @bf16_fp8e5m2_toward_zero_sat(bfloat %x) {
+define i8 @bf16_fp8e5m2_toward_zero_sat(bfloat %x) nounwind {
 ; CHECK-LABEL: bf16_fp8e5m2_toward_zero_sat:
 ; CHECK:       # %bb.0:
 ; CHECK-NEXT:    addi sp, sp, -32
-; CHECK-NEXT:    .cfi_def_cfa_offset 32
 ; CHECK-NEXT:    sd ra, 24(sp) # 8-byte Folded Spill
 ; CHECK-NEXT:    fsw fs0, 20(sp) # 4-byte Folded Spill
-; CHECK-NEXT:    .cfi_offset ra, -8
-; CHECK-NEXT:    .cfi_offset fs0, -12
 ; CHECK-NEXT:    fmv.x.w a0, fa0
 ; CHECK-NEXT:    slli a0, a0, 16
 ; CHECK-NEXT:    fmv.w.x fs0, a0
@@ -410,24 +389,18 @@ define i8 @bf16_fp8e5m2_toward_zero_sat(bfloat %x) {
 ; CHECK-NEXT:  .LBB3_11:
 ; CHECK-NEXT:    ld ra, 24(sp) # 8-byte Folded Reload
 ; CHECK-NEXT:    flw fs0, 20(sp) # 4-byte Folded Reload
-; CHECK-NEXT:    .cfi_restore ra
-; CHECK-NEXT:    .cfi_restore fs0
 ; CHECK-NEXT:    addi sp, sp, 32
-; CHECK-NEXT:    .cfi_def_cfa_offset 0
 ; CHECK-NEXT:    ret
   %r = call i8 @llvm.convert.to.arbitrary.fp(bfloat %x, metadata !"Float8E5M2", metadata !"round.towardzero", i1 true)
   ret i8 %r
 }
 
-define i8 @f32_fp8e5m2_nearest(float %x) {
+define i8 @f32_fp8e5m2_nearest(float %x) nounwind {
 ; CHECK-LABEL: f32_fp8e5m2_nearest:
 ; CHECK:       # %bb.0:
 ; CHECK-NEXT:    addi sp, sp, -32
-; CHECK-NEXT:    .cfi_def_cfa_offset 32
 ; CHECK-NEXT:    sd ra, 24(sp) # 8-byte Folded Spill
 ; CHECK-NEXT:    fsw fs0, 20(sp) # 4-byte Folded Spill
-; CHECK-NEXT:    .cfi_offset ra, -8
-; CHECK-NEXT:    .cfi_offset fs0, -12
 ; CHECK-NEXT:    fmv.s fs0, fa0
 ; CHECK-NEXT:    mv a0, sp
 ; CHECK-NEXT:    call frexpf
@@ -523,24 +496,18 @@ define i8 @f32_fp8e5m2_nearest(float %x) {
 ; CHECK-NEXT:  .LBB4_11:
 ; CHECK-NEXT:    ld ra, 24(sp) # 8-byte Folded Reload
 ; CHECK-NEXT:    flw fs0, 20(sp) # 4-byte Folded Reload
-; CHECK-NEXT:    .cfi_restore ra
-; CHECK-NEXT:    .cfi_restore fs0
 ; CHECK-NEXT:    addi sp, sp, 32
-; CHECK-NEXT:    .cfi_def_cfa_offset 0
 ; CHECK-NEXT:    ret
   %r = call i8 @llvm.convert.to.arbitrary.fp(float %x, metadata !"Float8E5M2", metadata !"round.tonearest", i1 false)
   ret i8 %r
 }
 
-define i8 @f32_fp8e5m2_toward_zero(float %x) {
+define i8 @f32_fp8e5m2_toward_zero(float %x) nounwind {
 ; CHECK-LABEL: f32_fp8e5m2_toward_zero:
 ; CHECK:       # %bb.0:
 ; CHECK-NEXT:    addi sp, sp, -32
-; CHECK-NEXT:    .cfi_def_cfa_offset 32
 ; CHECK-NEXT:    sd ra, 24(sp) # 8-byte Folded Spill
 ; CHECK-NEXT:    fsw fs0, 20(sp) # 4-byte Folded Spill
-; CHECK-NEXT:    .cfi_offset ra, -8
-; CHECK-NEXT:    .cfi_offset fs0, -12
 ; CHECK-NEXT:    fmv.s fs0, fa0
 ; CHECK-NEXT:    mv a0, sp
 ; CHECK-NEXT:    call frexpf
@@ -614,24 +581,18 @@ define i8 @f32_fp8e5m2_toward_zero(float %x) {
 ; CHECK-NEXT:  .LBB5_11:
 ; CHECK-NEXT:    ld ra, 24(sp) # 8-byte Folded Reload
 ; CHECK-NEXT:    flw fs0, 20(sp) # 4-byte Folded Reload
-; CHECK-NEXT:    .cfi_restore ra
-; CHECK-NEXT:    .cfi_restore fs0
 ; CHECK-NEXT:    addi sp, sp, 32
-; CHECK-NEXT:    .cfi_def_cfa_offset 0
 ; CHECK-NEXT:    ret
   %r = call i8 @llvm.convert.to.arbitrary.fp(float %x, metadata !"Float8E5M2", metadata !"round.towardzero", i1 false)
   ret i8 %r
 }
 
-define i8 @f32_fp8e5m2_nearest_sat(float %x) {
+define i8 @f32_fp8e5m2_nearest_sat(float %x) nounwind {
 ; CHECK-LABEL: f32_fp8e5m2_nearest_sat:
 ; CHECK:       # %bb.0:
 ; CHECK-NEXT:    addi sp, sp, -32
-; CHECK-NEXT:    .cfi_def_cfa_offset 32
 ; CHECK-NEXT:    sd ra, 24(sp) # 8-byte Folded Spill
 ; CHECK-NEXT:    fsw fs0, 20(sp) # 4-byte Folded Spill
-; CHECK-NEXT:    .cfi_offset ra, -8
-; CHECK-NEXT:    .cfi_offset fs0, -12
 ; CHECK-NEXT:    fmv.s fs0, fa0
 ; CHECK-NEXT:    mv a0, sp
 ; CHECK-NEXT:    call frexpf
@@ -726,24 +687,18 @@ define i8 @f32_fp8e5m2_nearest_sat(float %x) {
 ; CHECK-NEXT:  .LBB6_11:
 ; CHECK-NEXT:    ld ra, 24(sp) # 8-byte Folded Reload
 ; CHECK-NEXT:    flw fs0, 20(sp) # 4-byte Folded Reload
-; CHECK-NEXT:    .cfi_restore ra
-; CHECK-NEXT:    .cfi_restore fs0
 ; CHECK-NEXT:    addi sp, sp, 32
-; CHECK-NEXT:    .cfi_def_cfa_offset 0
 ; CHECK-NEXT:    ret
   %r = call i8 @llvm.convert.to.arbitrary.fp(float %x, metadata !"Float8E5M2", metadata !"round.tonearest", i1 true)
   ret i8 %r
 }
 
-define i8 @f32_fp8e5m2_toward_zero_sat(float %x) {
+define i8 @f32_fp8e5m2_toward_zero_sat(float %x) nounwind {
 ; CHECK-LABEL: f32_fp8e5m2_toward_zero_sat:
 ; CHECK:       # %bb.0:
 ; CHECK-NEXT:    addi sp, sp, -32
-; CHECK-NEXT:    .cfi_def_cfa_offset 32
 ; CHECK-NEXT:    sd ra, 24(sp) # 8-byte Folded Spill
 ; CHECK-NEXT:    fsw fs0, 20(sp) # 4-byte Folded Spill
-; CHECK-NEXT:    .cfi_offset ra, -8
-; CHECK-NEXT:    .cfi_offset fs0, -12
 ; CHECK-NEXT:    fmv.s fs0, fa0
 ; CHECK-NEXT:    mv a0, sp
 ; CHECK-NEXT:    call frexpf
@@ -816,10 +771,7 @@ define i8 @f32_fp8e5m2_toward_zero_sat(float %x) {
 ; CHECK-NEXT:  .LBB7_11:
 ; CHECK-NEXT:    ld ra, 24(sp) # 8-byte Folded Reload
 ; CHECK-NEXT:    flw fs0, 20(sp) # 4-byte Folded Reload
-; CHECK-NEXT:    .cfi_restore ra
-; CHECK-NEXT:    .cfi_restore fs0
 ; CHECK-NEXT:    addi sp, sp, 32
-; CHECK-NEXT:    .cfi_def_cfa_offset 0
 ; CHECK-NEXT:    ret
   %r = call i8 @llvm.convert.to.arbitrary.fp(float %x, metadata !"Float8E5M2", metadata !"round.towardzero", i1 true)
   ret i8 %r



More information about the llvm-branch-commits mailing list