[llvm] f4ecab1 - [SelectionDAG] Promote FPOWI/FLDEXP exponents where possible, and raise an error otherwise (#200621)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Jun 9 08:05:27 PDT 2026
Author: Justin Lebar
Date: 2026-06-09T08:05:22-07:00
New Revision: f4ecab143affd2c2c7953f58802673152fbd8c4b
URL: https://github.com/llvm/llvm-project/commit/f4ecab143affd2c2c7953f58802673152fbd8c4b
DIFF: https://github.com/llvm/llvm-project/commit/f4ecab143affd2c2c7953f58802673152fbd8c4b.diff
LOG: [SelectionDAG] Promote FPOWI/FLDEXP exponents where possible, and raise an error otherwise (#200621)
PromoteIntOp_ExpOp is reached when the exponent type is illegal.
- When the exponent type was smaller than int, we'd hit an assertion. In
builds where asserts were disabled, we actually ended up doing the right
thing; makeLibCall would sign-extend the value to int.
- When the exponent type was too large, we'd also hit an assertion. In
builds were asserts were disabled, we would *not* do the right thing;
we'd end up silently truncating the value. Now we explicitly raise an
error.
Added:
llvm/test/CodeGen/AArch64/powi-ldexp-promote-libcall-error.ll
Modified:
llvm/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp
llvm/test/CodeGen/AArch64/ldexp.ll
Removed:
################################################################################
diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp b/llvm/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp
index 86617b6dd33de..a5faff4f038cd 100644
--- a/llvm/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp
@@ -2821,10 +2821,22 @@ SDValue DAGTypeLegalizer::PromoteIntOp_ExpOp(SDNode *N) {
// we rewrite to a libcall here directly, letting makeLibCall handle promotion
// if the target accepts it according to shouldSignExtendTypeInLibCall.
- // The exponent should fit in a sizeof(int) type for the libcall to be valid.
- assert(DAG.getLibInfo().getIntSize() ==
- N->getOperand(1 + OpOffset).getValueType().getSizeInBits() &&
- "POWI exponent should match with sizeof(int) when doing the libcall.");
+ // A wider-than-int exponent can't be passed in an int (there's no wider
+ // libcall), so bail like the soften/expand paths. A narrower one is
+ // sign-extended to int by the makeLibCall below.
+ if (N->getOperand(1 + OpOffset).getScalarValueSizeInBits() >
+ DAG.getLibInfo().getIntSize()) {
+ const Function &Fn = DAG.getMachineFunction().getFunction();
+ Fn.getContext().diagnose(DiagnosticInfoLegalizationFailure(
+ Twine(IsPowI ? "powi" : "ldexp") +
+ " exponent does not match sizeof(int)",
+ Fn, N->getDebugLoc()));
+ if (IsStrict)
+ ReplaceValueWith(SDValue(N, 1), Chain);
+ ReplaceValueWith(SDValue(N, 0), DAG.getPOISON(N->getValueType(0)));
+ return SDValue();
+ }
+
TargetLowering::MakeLibCallOptions CallOptions;
CallOptions.setIsSigned(true);
SDValue Ops[2] = {N->getOperand(0 + OpOffset), N->getOperand(1 + OpOffset)};
diff --git a/llvm/test/CodeGen/AArch64/ldexp.ll b/llvm/test/CodeGen/AArch64/ldexp.ll
index 3c1b08b1fe8e6..a849a398eddb1 100644
--- a/llvm/test/CodeGen/AArch64/ldexp.ll
+++ b/llvm/test/CodeGen/AArch64/ldexp.ll
@@ -55,6 +55,37 @@ entry:
ret double %call
}
+; A sub-int exponent must be sign-extended to int on the libcall path;
+; PromoteIntOp_ExpOp must not crash on it.
+define double @testExpIntrinsic_i16(double %val, i16 %a) nounwind {
+; SVE-LABEL: testExpIntrinsic_i16:
+; SVE: // %bb.0: // %entry
+; SVE-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill
+; SVE-NEXT: sxth w0, w0
+; SVE-NEXT: bl ldexp
+; SVE-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload
+; SVE-NEXT: ret
+;
+; GISEL-LABEL: testExpIntrinsic_i16:
+; GISEL: // %bb.0: // %entry
+; GISEL-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill
+; GISEL-NEXT: sxth w0, w0
+; GISEL-NEXT: bl ldexp
+; GISEL-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload
+; GISEL-NEXT: ret
+;
+; WINDOWS-LABEL: testExpIntrinsic_i16:
+; WINDOWS: // %bb.0: // %entry
+; WINDOWS-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill
+; WINDOWS-NEXT: sxth w0, w0
+; WINDOWS-NEXT: bl ldexp
+; WINDOWS-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload
+; WINDOWS-NEXT: ret
+entry:
+ %call = tail call fast double @llvm.ldexp.f64.i16(double %val, i16 %a)
+ ret double %call
+}
+
define float @testExpf(float %val, i32 %a) {
; SVELINUX-LABEL: testExpf:
; SVELINUX: // %bb.0: // %entry
diff --git a/llvm/test/CodeGen/AArch64/powi-ldexp-promote-libcall-error.ll b/llvm/test/CodeGen/AArch64/powi-ldexp-promote-libcall-error.ll
new file mode 100644
index 0000000000000..55463495e5356
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/powi-ldexp-promote-libcall-error.ll
@@ -0,0 +1,24 @@
+; RUN: not llc -mtriple=aarch64 -filetype=null %s 2>&1 | FileCheck %s
+
+; A powi/ldexp exponent wider than sizeof(int) can't be passed to the libcall,
+; so PromoteIntOp_ExpOp must emit a clean error rather than crash (assertions)
+; or silently truncate. i48 is illegal and promoted through that path here; i64
+; would be legal and i128 expanded, so neither would reach it.
+
+; CHECK: error: {{.*}}ldexp exponent does not match sizeof(int)
+define double @ldexp_f64_i48(double %val, i48 %a) {
+ %call = call double @llvm.ldexp.f64.i48(double %val, i48 %a)
+ ret double %call
+}
+
+; CHECK: error: {{.*}}powi exponent does not match sizeof(int)
+define double @powi_f64_i48(double %val, i48 %a) {
+ %call = call double @llvm.powi.f64.i48(double %val, i48 %a)
+ ret double %call
+}
+
+; CHECK: error: {{.*}}ldexp exponent does not match sizeof(int)
+define double @ldexp_f64_i48_strictfp(double %val, i48 %a) strictfp {
+ %call = call double @llvm.experimental.constrained.ldexp.f64.i48(double %val, i48 %a, metadata !"round.tonearest", metadata !"fpexcept.strict")
+ ret double %call
+}
More information about the llvm-commits
mailing list