[llvm] [DAGTypeLegalizer] Add missing BR_CC handler for soft-promoted half operands (PR #196214)

Tony Varghese via llvm-commits llvm-commits at lists.llvm.org
Wed May 6 18:09:07 PDT 2026


https://github.com/tonykuttai created https://github.com/llvm/llvm-project/pull/196214

`SoftPromoteHalfOperand` had no case for `ISD::BR_CC`, causing a crash when a half-typed `fcmp` result fed directly into a conditional branch. All other comparison-related nodes (`SETCC, SELECT_CC`) were already handled. Add `SoftPromoteHalfOp_BR_CC` following the same pattern as `SoftPromoteHalfOp_SELECT_CC`.

Fixes #195562

>From 40b9897cfab3244a67a8ab6b5d751c17ff924728 Mon Sep 17 00:00:00 2001
From: Tony Varghese <tony.varghese at ibm.com>
Date: Wed, 6 May 2026 10:01:23 +0530
Subject: [PATCH] [DAGTypeLegalizer] Add missing BR_CC handler for
 soft-promoted half operands

SoftPromoteHalfOperand had no case for ISD::BR_CC, causing a crash
when a half-typed fcmp result fed directly into a conditional branch.
All other comparison-related nodes (SETCC, SELECT_CC) were already
handled. Add SoftPromoteHalfOp_BR_CC following the same pattern as
SoftPromoteHalfOp_SELECT_CC.

Fixes #195562
---
 .../SelectionDAG/LegalizeFloatTypes.cpp       |  27 +++
 llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h |   1 +
 .../PowerPC/soft-promote-half-br-cc.ll        | 170 ++++++++++++++++++
 3 files changed, 198 insertions(+)
 create mode 100644 llvm/test/CodeGen/PowerPC/soft-promote-half-br-cc.ll

diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp b/llvm/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp
index 25f4f75eaedea..26a749f91baf0 100644
--- a/llvm/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp
@@ -3197,6 +3197,9 @@ bool DAGTypeLegalizer::SoftPromoteHalfOperand(SDNode *N, unsigned OpNo) {
   case ISD::STRICT_FP_EXTEND:
   case ISD::FP_EXTEND:  Res = SoftPromoteHalfOp_FP_EXTEND(N); break;
   case ISD::SELECT_CC:  Res = SoftPromoteHalfOp_SELECT_CC(N, OpNo); break;
+  case ISD::BR_CC:
+    Res = SoftPromoteHalfOp_BR_CC(N);
+    break;
   case ISD::SETCC:      Res = SoftPromoteHalfOp_SETCC(N); break;
   case ISD::STORE:      Res = SoftPromoteHalfOp_STORE(N, OpNo); break;
   case ISD::ATOMIC_STORE:
@@ -3309,6 +3312,30 @@ SDValue DAGTypeLegalizer::SoftPromoteHalfOp_FP_TO_XINT_SAT(SDNode *N) {
                      N->getOperand(1));
 }
 
+SDValue DAGTypeLegalizer::SoftPromoteHalfOp_BR_CC(SDNode *N) {
+  // BR_CC: chain(0), condcode(1), LHS(2), RHS(3), dest(4)
+  // The comparison operands (LHS, RHS) are soft-promoted halfs.
+  SDValue Op0 = N->getOperand(2);
+  SDValue Op1 = N->getOperand(3);
+  SDLoc dl(N);
+
+  EVT SVT = Op0.getValueType();
+  EVT NVT = TLI.getTypeToTransformTo(*DAG.getContext(), SVT);
+
+  // Get the soft-promoted i16 values
+  Op0 = GetSoftPromotedHalf(Op0);
+  Op1 = GetSoftPromotedHalf(Op1);
+
+  // Promote both comparison operands to the larger FP type.
+  auto PromotionOpcode = GetPromotionOpcode(SVT, NVT);
+  Op0 = DAG.getNode(PromotionOpcode, dl, NVT, Op0);
+  Op1 = DAG.getNode(PromotionOpcode, dl, NVT, Op1);
+
+  // Create a new BR_CC node with promoted operands
+  return DAG.getNode(ISD::BR_CC, dl, MVT::Other, N->getOperand(0),
+                     N->getOperand(1), Op0, Op1, N->getOperand(4));
+}
+
 SDValue DAGTypeLegalizer::SoftPromoteHalfOp_SELECT_CC(SDNode *N,
                                                       unsigned OpNo) {
   assert(OpNo == 0 && "Can only soften the comparison values");
diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h b/llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h
index 89698a2c77123..84d5b454ba28e 100644
--- a/llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h
+++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h
@@ -806,6 +806,7 @@ class LLVM_LIBRARY_VISIBILITY DAGTypeLegalizer {
   SDValue SoftPromoteHalfOp_FP_TO_XINT_SAT(SDNode *N);
   SDValue SoftPromoteHalfOp_SETCC(SDNode *N);
   SDValue SoftPromoteHalfOp_SELECT_CC(SDNode *N, unsigned OpNo);
+  SDValue SoftPromoteHalfOp_BR_CC(SDNode *N);
   SDValue SoftPromoteHalfOp_STORE(SDNode *N, unsigned OpNo);
   SDValue SoftPromoteHalfOp_ATOMIC_STORE(SDNode *N, unsigned OpNo);
   SDValue SoftPromoteHalfOp_STACKMAP(SDNode *N, unsigned OpNo);
diff --git a/llvm/test/CodeGen/PowerPC/soft-promote-half-br-cc.ll b/llvm/test/CodeGen/PowerPC/soft-promote-half-br-cc.ll
new file mode 100644
index 0000000000000..ff4e362f4748a
--- /dev/null
+++ b/llvm/test/CodeGen/PowerPC/soft-promote-half-br-cc.ll
@@ -0,0 +1,170 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -verify-machineinstrs -mtriple=powerpc64le-unknown-linux-gnu \
+; RUN:     -mcpu=pwr9 < %s | FileCheck %s --check-prefix=CHECK-P9
+; RUN: llc -verify-machineinstrs -mtriple=powerpc64le-unknown-linux-gnu \
+; RUN:     -mcpu=pwr8 < %s | FileCheck %s --check-prefix=CHECK-P8
+
+; Basic comparison with branch
+define i32 @test_br_cc_olt(half %a, half %b) {
+; CHECK-P9-LABEL: test_br_cc_olt:
+; CHECK-P9:       # %bb.0:
+; CHECK-P9-NEXT:    clrlwi 3, 3, 16
+; CHECK-P9-NEXT:    clrlwi 4, 4, 16
+; CHECK-P9-NEXT:    mtfprwz 0, 4
+; CHECK-P9-NEXT:    mtfprwz 1, 3
+; CHECK-P9-NEXT:    xscvhpdp 0, 0
+; CHECK-P9-NEXT:    xscvhpdp 1, 1
+; CHECK-P9-NEXT:    fcmpu 0, 1, 0
+; CHECK-P9-NEXT:    bge 0, .LBB0_2
+; CHECK-P9-NEXT:  # %bb.1: # %if.then
+; CHECK-P9-NEXT:    li 3, 1
+; CHECK-P9-NEXT:    blr
+; CHECK-P9-NEXT:  .LBB0_2: # %if.else
+; CHECK-P9-NEXT:    li 3, 0
+; CHECK-P9-NEXT:    blr
+;
+; CHECK-P8-LABEL: test_br_cc_olt:
+; CHECK-P8:       # %bb.0:
+; CHECK-P8-NEXT:    mflr 0
+; CHECK-P8-NEXT:    .cfi_def_cfa_offset 64
+; CHECK-P8-NEXT:    .cfi_offset lr, 16
+; CHECK-P8-NEXT:    .cfi_offset r30, -24
+; CHECK-P8-NEXT:    .cfi_offset f31, -8
+; CHECK-P8-NEXT:    std 30, -24(1) # 8-byte Folded Spill
+; CHECK-P8-NEXT:    stfd 31, -8(1) # 8-byte Folded Spill
+; CHECK-P8-NEXT:    stdu 1, -64(1)
+; CHECK-P8-NEXT:    mr 30, 3
+; CHECK-P8-NEXT:    clrldi 3, 4, 48
+; CHECK-P8-NEXT:    std 0, 80(1)
+; CHECK-P8-NEXT:    bl __extendhfsf2
+; CHECK-P8-NEXT:    nop
+; CHECK-P8-NEXT:    clrldi 3, 30, 48
+; CHECK-P8-NEXT:    fmr 31, 1
+; CHECK-P8-NEXT:    bl __extendhfsf2
+; CHECK-P8-NEXT:    nop
+; CHECK-P8-NEXT:    fcmpu 0, 1, 31
+; CHECK-P8-NEXT:    bge 0, .LBB0_2
+; CHECK-P8-NEXT:  # %bb.1: # %if.then
+; CHECK-P8-NEXT:    li 3, 1
+; CHECK-P8-NEXT:    b .LBB0_3
+; CHECK-P8-NEXT:  .LBB0_2: # %if.else
+; CHECK-P8-NEXT:    li 3, 0
+; CHECK-P8-NEXT:  .LBB0_3: # %if.then
+; CHECK-P8-NEXT:    addi 1, 1, 64
+; CHECK-P8-NEXT:    ld 0, 16(1)
+; CHECK-P8-NEXT:    lfd 31, -8(1) # 8-byte Folded Reload
+; CHECK-P8-NEXT:    ld 30, -24(1) # 8-byte Folded Reload
+; CHECK-P8-NEXT:    mtlr 0
+; CHECK-P8-NEXT:    blr
+  %cmp = fcmp olt half %a, %b
+  br i1 %cmp, label %if.then, label %if.else
+if.then:
+  ret i32 1
+if.else:
+  ret i32 0
+}
+
+; Test with constant
+define i32 @test_br_cc_constant(half %a) {
+; CHECK-P9-LABEL: test_br_cc_constant:
+; CHECK-P9:       # %bb.0:
+; CHECK-P9-NEXT:    clrlwi 3, 3, 16
+; CHECK-P9-NEXT:    xxlxor 1, 1, 1
+; CHECK-P9-NEXT:    mtfprwz 0, 3
+; CHECK-P9-NEXT:    xscvhpdp 0, 0
+; CHECK-P9-NEXT:    fcmpu 0, 0, 1
+; CHECK-P9-NEXT:    ble 0, .LBB1_2
+; CHECK-P9-NEXT:  # %bb.1: # %if.then
+; CHECK-P9-NEXT:    li 3, 1
+; CHECK-P9-NEXT:    blr
+; CHECK-P9-NEXT:  .LBB1_2: # %if.else
+; CHECK-P9-NEXT:    li 3, 0
+; CHECK-P9-NEXT:    blr
+;
+; CHECK-P8-LABEL: test_br_cc_constant:
+; CHECK-P8:       # %bb.0:
+; CHECK-P8-NEXT:    mflr 0
+; CHECK-P8-NEXT:    stdu 1, -32(1)
+; CHECK-P8-NEXT:    std 0, 48(1)
+; CHECK-P8-NEXT:    .cfi_def_cfa_offset 32
+; CHECK-P8-NEXT:    .cfi_offset lr, 16
+; CHECK-P8-NEXT:    clrldi 3, 3, 48
+; CHECK-P8-NEXT:    bl __extendhfsf2
+; CHECK-P8-NEXT:    nop
+; CHECK-P8-NEXT:    xxlxor 0, 0, 0
+; CHECK-P8-NEXT:    fcmpu 0, 1, 0
+; CHECK-P8-NEXT:    ble 0, .LBB1_2
+; CHECK-P8-NEXT:  # %bb.1: # %if.then
+; CHECK-P8-NEXT:    li 3, 1
+; CHECK-P8-NEXT:    b .LBB1_3
+; CHECK-P8-NEXT:  .LBB1_2: # %if.else
+; CHECK-P8-NEXT:    li 3, 0
+; CHECK-P8-NEXT:  .LBB1_3: # %if.then
+; CHECK-P8-NEXT:    addi 1, 1, 32
+; CHECK-P8-NEXT:    ld 0, 16(1)
+; CHECK-P8-NEXT:    mtlr 0
+; CHECK-P8-NEXT:    blr
+  %cmp = fcmp ogt half %a, 0xH0000
+  br i1 %cmp, label %if.then, label %if.else
+if.then:
+  ret i32 1
+if.else:
+  ret i32 0
+}
+
+; vector reduction + branch
+define fastcc i16 @test_vector_reduce_br(half %arg) {
+; CHECK-P9-LABEL: test_vector_reduce_br:
+; CHECK-P9:       # %bb.0:
+; CHECK-P9-NEXT:    clrlwi 3, 3, 16
+; CHECK-P9-NEXT:    xxlxor 1, 1, 1
+; CHECK-P9-NEXT:    mtfprwz 0, 3
+; CHECK-P9-NEXT:    xscvhpdp 0, 0
+; CHECK-P9-NEXT:    fcmpu 0, 0, 1
+; CHECK-P9-NEXT:    bc 12, 0, .LBB2_3
+; CHECK-P9-NEXT:  # %bb.1:
+; CHECK-P9-NEXT:    fcmpu 0, 0, 0
+; CHECK-P9-NEXT:    bc 12, 3, .LBB2_3
+; CHECK-P9-NEXT:  # %bb.2: # %taken
+; CHECK-P9-NEXT:    li 3, 0
+; CHECK-P9-NEXT:    blr
+; CHECK-P9-NEXT:  .LBB2_3: # %not_taken
+; CHECK-P9-NEXT:    li 3, 1
+; CHECK-P9-NEXT:    blr
+;
+; CHECK-P8-LABEL: test_vector_reduce_br:
+; CHECK-P8:       # %bb.0:
+; CHECK-P8-NEXT:    mflr 0
+; CHECK-P8-NEXT:    stdu 1, -32(1)
+; CHECK-P8-NEXT:    std 0, 48(1)
+; CHECK-P8-NEXT:    .cfi_def_cfa_offset 32
+; CHECK-P8-NEXT:    .cfi_offset lr, 16
+; CHECK-P8-NEXT:    clrldi 3, 3, 48
+; CHECK-P8-NEXT:    bl __extendhfsf2
+; CHECK-P8-NEXT:    nop
+; CHECK-P8-NEXT:    xxlxor 0, 0, 0
+; CHECK-P8-NEXT:    fcmpu 0, 1, 0
+; CHECK-P8-NEXT:    bc 12, 0, .LBB2_3
+; CHECK-P8-NEXT:  # %bb.1:
+; CHECK-P8-NEXT:    fcmpu 0, 1, 1
+; CHECK-P8-NEXT:    bc 12, 3, .LBB2_3
+; CHECK-P8-NEXT:  # %bb.2: # %taken
+; CHECK-P8-NEXT:    li 3, 0
+; CHECK-P8-NEXT:    b .LBB2_4
+; CHECK-P8-NEXT:  .LBB2_3: # %not_taken
+; CHECK-P8-NEXT:    li 3, 1
+; CHECK-P8-NEXT:  .LBB2_4: # %taken
+; CHECK-P8-NEXT:    addi 1, 1, 32
+; CHECK-P8-NEXT:    ld 0, 16(1)
+; CHECK-P8-NEXT:    mtlr 0
+; CHECK-P8-NEXT:    blr
+  %reduce = tail call half @llvm.vector.reduce.fmin.v4f16(<4 x half> zeroinitializer)
+  %cmp = fcmp ole half %reduce, %arg
+  br i1 %cmp, label %taken, label %not_taken
+taken:
+  ret i16 0
+not_taken:
+  ret i16 1
+}
+
+declare half @llvm.vector.reduce.fmin.v4f16(<4 x half>)



More information about the llvm-commits mailing list