[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