[llvm] [GlobalISel] Translate `fcmp {true, false}` to constant values (PR #218780)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Aug 25 13:46:59 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-backend-risc-v
Author: Afonso Bordado (afonso360)
<details>
<summary>Changes</summary>
👋 Hey,
RISC-V does not have floating point instructions as part of its base ISA. Instead it relies on expanding these instructions into libcalls during instruction selection.
It looks like there are no such libcalls for `fcmp {true,false}`, so instead of implementing it, or expanding these instructions, we can avoid such IR translations in the first place by replacing `fcmp {true,false}` with an appropriate constant.
There are two places in IRTranslation that insert `fcmp`'s and one of them already performs this "optimization", so this commit mostly ensures that both places go through a single unifying path.
This avoids a crash in the included testcase for RISC-V when compiled with O0 ([Godbolt](https://godbolt.org/z/xa18Wd3Gn)). The testcase was found by running the isel fuzzer, and then minimized.
---
I don't know if this way of fixing the issue is preferable to just letting the backend expand these operations, please let me know, and I'm happy to open a different PR.
---
Full diff: https://github.com/llvm/llvm-project/pull/218780.diff
2 Files Affected:
- (modified) llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp (+26-8)
- (added) llvm/test/CodeGen/RISCV/GlobalISel/float-condbr-fcmp.ll (+107)
``````````diff
diff --git a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
index baac98561f25b..dfdec383105a4 100644
--- a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
@@ -474,6 +474,11 @@ class IRTranslatorImpl {
MachineBasicBlock *DefaultMBB,
MachineIRBuilder &MIB);
+ MachineInstrBuilder
+ buildFCmpOrConstant(MachineIRBuilder &MIB, CmpInst::Predicate Pred,
+ const DstOp &Res, const SrcOp &Op0, const SrcOp &Op1,
+ std::optional<unsigned> Flags = std::nullopt);
+
bool translateSwitch(const User &U, MachineIRBuilder &MIRBuilder);
// End switch lowering section.
@@ -1111,6 +1116,24 @@ bool IRTranslatorImpl::translateFNeg(const User &U,
return translateUnaryOp(TargetOpcode::G_FNEG, U, MIRBuilder);
}
+MachineInstrBuilder IRTranslatorImpl::buildFCmpOrConstant(
+ MachineIRBuilder &MIB, CmpInst::Predicate Pred, const DstOp &Res,
+ const SrcOp &Op0, const SrcOp &Op1, std::optional<unsigned> Flags) {
+
+ if (Pred != CmpInst::FCMP_FALSE && Pred != CmpInst::FCMP_TRUE)
+ return MIB.buildFCmp(Pred, Res, Op0, Op1, Flags);
+
+ // For FCMP_FALSE and FCMP_TRUE, lower it to a constant value.
+ LLT ResTy = Res.getLLTTy(*MIB.getMRI());
+ Type *ResIRTy = getTypeForLLT(ResTy, MIB.getContext());
+
+ Constant *C = Pred == CmpInst::FCMP_FALSE
+ ? Constant::getNullValue(ResIRTy)
+ : Constant::getAllOnesValue(ResIRTy);
+
+ return MIB.buildCopy(Res, getOrCreateVReg(*C));
+}
+
bool IRTranslatorImpl::translateCompare(const User &U,
MachineIRBuilder &MIRBuilder) {
if (!mayTranslateUserTypes(U))
@@ -1124,14 +1147,8 @@ bool IRTranslatorImpl::translateCompare(const User &U,
uint32_t Flags = MachineInstr::copyFlagsFromInstruction(*CI);
if (CmpInst::isIntPredicate(Pred))
MIRBuilder.buildICmp(Pred, Res, Op0, Op1, Flags);
- else if (Pred == CmpInst::FCMP_FALSE)
- MIRBuilder.buildCopy(
- Res, getOrCreateVReg(*Constant::getNullValue(U.getType())));
- else if (Pred == CmpInst::FCMP_TRUE)
- MIRBuilder.buildCopy(
- Res, getOrCreateVReg(*Constant::getAllOnesValue(U.getType())));
else
- MIRBuilder.buildFCmp(Pred, Res, Op0, Op1, Flags);
+ buildFCmpOrConstant(MIRBuilder, Pred, Res, Op0, Op1, Flags);
return true;
}
@@ -1713,7 +1730,8 @@ void IRTranslatorImpl::emitSwitchCase(SwitchCG::CaseBlock &CB,
Register CondRHS = getOrCreateVReg(*CB.CmpRHS);
if (CmpInst::isFPPredicate(CB.PredInfo.Pred))
Cond =
- MIB.buildFCmp(CB.PredInfo.Pred, i1Ty, CondLHS, CondRHS).getReg(0);
+ buildFCmpOrConstant(MIB, CB.PredInfo.Pred, i1Ty, CondLHS, CondRHS)
+ .getReg(0);
else
Cond =
MIB.buildICmp(CB.PredInfo.Pred, i1Ty, CondLHS, CondRHS).getReg(0);
diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/float-condbr-fcmp.ll b/llvm/test/CodeGen/RISCV/GlobalISel/float-condbr-fcmp.ll
new file mode 100644
index 0000000000000..d8bffc4708541
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/float-condbr-fcmp.ll
@@ -0,0 +1,107 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple=riscv32 -global-isel -global-isel-abort=1 -O0 < %s \
+; RUN: | FileCheck -check-prefix=RV32I %s
+; RUN: llc -mtriple=riscv64 -global-isel -global-isel-abort=1 -O0 < %s \
+; RUN: | FileCheck -check-prefix=RV64I %s
+
+
+define i64 @and_fcmp_true() {
+; RV32I-LABEL: and_fcmp_true:
+; RV32I: # %bb.0: # %BB
+; RV32I-NEXT: addi sp, sp, -16
+; RV32I-NEXT: .cfi_def_cfa_offset 16
+; RV32I-NEXT: li a0, 1
+; RV32I-NEXT: sw a0, 8(sp) # 4-byte Folded Spill
+; RV32I-NEXT: li a0, 0
+; RV32I-NEXT: li a1, 0
+; RV32I-NEXT: sw a1, 12(sp) # 4-byte Folded Spill
+; RV32I-NEXT: bnez a0, .LBB0_1
+; RV32I-NEXT: j .LBB0_2
+; RV32I-NEXT: .LBB0_1: # %BB
+; RV32I-NEXT: lw a0, 8(sp) # 4-byte Folded Reload
+; RV32I-NEXT: bnez a0, .LBB0_2
+; RV32I-NEXT: j .LBB0_2
+; RV32I-NEXT: .LBB0_2: # %BB1
+; RV32I-NEXT: lw a1, 12(sp) # 4-byte Folded Reload
+; RV32I-NEXT: mv a0, a1
+; RV32I-NEXT: addi sp, sp, 16
+; RV32I-NEXT: .cfi_def_cfa_offset 0
+; RV32I-NEXT: ret
+;
+; RV64I-LABEL: and_fcmp_true:
+; RV64I: # %bb.0: # %BB
+; RV64I-NEXT: addi sp, sp, -16
+; RV64I-NEXT: .cfi_def_cfa_offset 16
+; RV64I-NEXT: li a0, 1
+; RV64I-NEXT: sd a0, 0(sp) # 8-byte Folded Spill
+; RV64I-NEXT: li a0, 0
+; RV64I-NEXT: li a1, 0
+; RV64I-NEXT: sd a1, 8(sp) # 8-byte Folded Spill
+; RV64I-NEXT: bnez a0, .LBB0_1
+; RV64I-NEXT: j .LBB0_2
+; RV64I-NEXT: .LBB0_1: # %BB
+; RV64I-NEXT: ld a0, 0(sp) # 8-byte Folded Reload
+; RV64I-NEXT: bnez a0, .LBB0_2
+; RV64I-NEXT: j .LBB0_2
+; RV64I-NEXT: .LBB0_2: # %BB1
+; RV64I-NEXT: ld a0, 8(sp) # 8-byte Folded Reload
+; RV64I-NEXT: addi sp, sp, 16
+; RV64I-NEXT: .cfi_def_cfa_offset 0
+; RV64I-NEXT: ret
+BB:
+ %C1 = fcmp true float 0.000000e+00, 0.000000e+00
+ %B1 = and i1 false, %C1
+ br i1 %B1, label %BB1, label %BB1
+BB1:
+ ret i64 0
+}
+
+
+define i64 @and_fcmp_false() {
+; RV32I-LABEL: and_fcmp_false:
+; RV32I: # %bb.0: # %BB
+; RV32I-NEXT: addi sp, sp, -16
+; RV32I-NEXT: .cfi_def_cfa_offset 16
+; RV32I-NEXT: li a0, 0
+; RV32I-NEXT: sw a0, 8(sp) # 4-byte Folded Spill
+; RV32I-NEXT: li a1, 0
+; RV32I-NEXT: sw a1, 12(sp) # 4-byte Folded Spill
+; RV32I-NEXT: bnez a0, .LBB1_1
+; RV32I-NEXT: j .LBB1_2
+; RV32I-NEXT: .LBB1_1: # %BB
+; RV32I-NEXT: lw a0, 8(sp) # 4-byte Folded Reload
+; RV32I-NEXT: bnez a0, .LBB1_2
+; RV32I-NEXT: j .LBB1_2
+; RV32I-NEXT: .LBB1_2: # %BB1
+; RV32I-NEXT: lw a1, 12(sp) # 4-byte Folded Reload
+; RV32I-NEXT: mv a0, a1
+; RV32I-NEXT: addi sp, sp, 16
+; RV32I-NEXT: .cfi_def_cfa_offset 0
+; RV32I-NEXT: ret
+;
+; RV64I-LABEL: and_fcmp_false:
+; RV64I: # %bb.0: # %BB
+; RV64I-NEXT: addi sp, sp, -16
+; RV64I-NEXT: .cfi_def_cfa_offset 16
+; RV64I-NEXT: li a0, 0
+; RV64I-NEXT: sd a0, 0(sp) # 8-byte Folded Spill
+; RV64I-NEXT: li a1, 0
+; RV64I-NEXT: sd a1, 8(sp) # 8-byte Folded Spill
+; RV64I-NEXT: bnez a0, .LBB1_1
+; RV64I-NEXT: j .LBB1_2
+; RV64I-NEXT: .LBB1_1: # %BB
+; RV64I-NEXT: ld a0, 0(sp) # 8-byte Folded Reload
+; RV64I-NEXT: bnez a0, .LBB1_2
+; RV64I-NEXT: j .LBB1_2
+; RV64I-NEXT: .LBB1_2: # %BB1
+; RV64I-NEXT: ld a0, 8(sp) # 8-byte Folded Reload
+; RV64I-NEXT: addi sp, sp, 16
+; RV64I-NEXT: .cfi_def_cfa_offset 0
+; RV64I-NEXT: ret
+BB:
+ %C1 = fcmp false float 0.000000e+00, 0.000000e+00
+ %B1 = and i1 false, %C1
+ br i1 %B1, label %BB1, label %BB1
+BB1:
+ ret i64 0
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/218780
More information about the llvm-commits
mailing list