From eb47c52fbd6788c9d39fe90fa4b39837c4e72ab9 Mon Sep 17 00:00:00 2001 From: "Gorban, Igor" Date: Fri, 14 Nov 2025 13:00:22 +0100 Subject: [PATCH 1/2] [InstSimplify] Fix crash when optimizing minmax with bitcast constant vectors When simplifying min/max intrinsics with fixed-size vector constants, InstructionSimplify attempts to optimize element-wise. However, getAggregateElement() can return null for certain constant expressions like bitcasts, leading to a null pointer dereference. This patch adds a check to bail out of the optimization when getAggregateElement() returns null, preventing the crash while maintaining correct behavior for normal constant vectors. Fixes crash with patterns like: call <2 x half> @llvm.minnum.v2f16(<2 x half> %x, <2 x half> bitcast (<1 x i32> to <2 x half>)) --- llvm/lib/Analysis/InstructionSimplify.cpp | 4 ++ .../Transforms/InstSimplify/fminmax-folds.ll | 70 +++++++++++++++++++ 2 files changed, 74 insertions(+) diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp index 2a0a6a2d302b1..e5d2842a0ae7b 100644 --- a/llvm/lib/Analysis/InstructionSimplify.cpp +++ b/llvm/lib/Analysis/InstructionSimplify.cpp @@ -6985,6 +6985,10 @@ Value *llvm::simplifyBinaryIntrinsic(Intrinsic::ID IID, Type *ReturnType, // VectorShuffle instruction, which is not allowed in simplifyBinOp. OptResult = MinMaxOptResult::UseEither; for (unsigned i = 0; i != ElemCount.getFixedValue(); ++i) { + if (!C->getAggregateElement(i)) { + OptResult = MinMaxOptResult::CannotOptimize; + break; + } auto ElemResult = OptimizeConstMinMax(C->getAggregateElement(i), IID, Call, &NewConst); if (ElemResult == MinMaxOptResult::CannotOptimize || diff --git a/llvm/test/Transforms/InstSimplify/fminmax-folds.ll b/llvm/test/Transforms/InstSimplify/fminmax-folds.ll index 3a03f8627ab68..091e85920c0df 100644 --- a/llvm/test/Transforms/InstSimplify/fminmax-folds.ll +++ b/llvm/test/Transforms/InstSimplify/fminmax-folds.ll @@ -885,3 +885,73 @@ define void @minmax_minmax_xy_maxmin_yx(double %x, double %y, ptr %minnum_res, p store double %final_maximumnum, ptr %maximumnum_res ret void } + +;############################################################### +;# Constant Expression Vector Tests # +;############################################################### +; Test that minmax intrinsics with constant expression vectors don't crash +; when getAggregateElement returns null for certain constant expressions. +; These tests cover various scenarios where getAggregateElement() fails: +; - Bitcast from mismatched vector element counts +; - Bitcast from integer to float vectors +; - Bitcast from i64 with different element boundaries + +; Test with bitcast from <1 x i32> to <2 x half> (element count mismatch) +define <2 x half> @minmax_bitcast_v2f16_minnum(<2 x half> %x) { +; CHECK-LABEL: @minmax_bitcast_v2f16_minnum( +; CHECK-NEXT: [[RESULT:%.*]] = call <2 x half> @llvm.minnum.v2f16(<2 x half> [[X:%.*]], <2 x half> bitcast (<1 x i32> splat (i32 1078530011) to <2 x half>)) +; CHECK-NEXT: ret <2 x half> [[RESULT]] +; + %result = call <2 x half> @llvm.minnum.v2f16(<2 x half> %x, <2 x half> bitcast (<1 x i32> to <2 x half>)) + ret <2 x half> %result +} + +; Test with bitcast from <2 x i32> to <4 x half> (different element boundaries) +define <4 x half> @minmax_bitcast_v4f16_maxnum(<4 x half> %x) { +; CHECK-LABEL: @minmax_bitcast_v4f16_maxnum( +; CHECK-NEXT: [[RESULT:%.*]] = call <4 x half> @llvm.maxnum.v4f16(<4 x half> [[X:%.*]], <4 x half> bitcast (<2 x i32> to <4 x half>)) +; CHECK-NEXT: ret <4 x half> [[RESULT]] +; + %result = call <4 x half> @llvm.maxnum.v4f16(<4 x half> %x, <4 x half> bitcast (<2 x i32> to <4 x half>)) + ret <4 x half> %result +} + +; Test with bitcast from <1 x i64> to <2 x float> (scalar to vector bitcast) +define <2 x float> @minmax_bitcast_v2f32_minimum(<2 x float> %x) { +; CHECK-LABEL: @minmax_bitcast_v2f32_minimum( +; CHECK-NEXT: [[RESULT:%.*]] = call <2 x float> @llvm.minimum.v2f32(<2 x float> [[X:%.*]], <2 x float> bitcast (<1 x i64> splat (i64 4638564619268087808) to <2 x float>)) +; CHECK-NEXT: ret <2 x float> [[RESULT]] +; + %result = call <2 x float> @llvm.minimum.v2f32(<2 x float> %x, <2 x float> bitcast (<1 x i64> to <2 x float>)) + ret <2 x float> %result +} + +; Test with bitcast from <1 x double> to <4 x half> (type size mismatch) +define <4 x half> @minmax_bitcast_v4f16_maximum(<4 x half> %x) { +; CHECK-LABEL: @minmax_bitcast_v4f16_maximum( +; CHECK-NEXT: [[RESULT:%.*]] = call <4 x half> @llvm.maximum.v4f16(<4 x half> [[X:%.*]], <4 x half> bitcast (<1 x double> splat (double 0x400921FB54442D18) to <4 x half>)) +; CHECK-NEXT: ret <4 x half> [[RESULT]] +; + %result = call <4 x half> @llvm.maximum.v4f16(<4 x half> %x, <4 x half> bitcast (<1 x double> to <4 x half>)) + ret <4 x half> %result +} + +; Test with bitcast from <2 x i16> to <2 x half> (integer to float) +define <2 x half> @minmax_bitcast_v2f16_minimumnum(<2 x half> %x) { +; CHECK-LABEL: @minmax_bitcast_v2f16_minimumnum( +; CHECK-NEXT: [[RESULT:%.*]] = call <2 x half> @llvm.minimumnum.v2f16(<2 x half> [[X:%.*]], <2 x half> ) +; CHECK-NEXT: ret <2 x half> [[RESULT]] +; + %result = call <2 x half> @llvm.minimumnum.v2f16(<2 x half> %x, <2 x half> bitcast (<2 x i16> to <2 x half>)) + ret <2 x half> %result +} + +; Test with bitcast from <4 x i16> to <4 x half> (matching element count but getAggregateElement may fail) +define <4 x half> @minmax_bitcast_v4f16_maximumnum(<4 x half> %x) { +; CHECK-LABEL: @minmax_bitcast_v4f16_maximumnum( +; CHECK-NEXT: [[RESULT:%.*]] = call <4 x half> @llvm.maximumnum.v4f16(<4 x half> [[X:%.*]], <4 x half> ) +; CHECK-NEXT: ret <4 x half> [[RESULT]] +; + %result = call <4 x half> @llvm.maximumnum.v4f16(<4 x half> %x, <4 x half> bitcast (<4 x i16> to <4 x half>)) + ret <4 x half> %result +} From 8c9b67764c80e8ac23ffec9ea72a3a29bc5978e6 Mon Sep 17 00:00:00 2001 From: "Gorban, Igor" Date: Fri, 14 Nov 2025 18:44:45 +0100 Subject: [PATCH 2/2] Apply suggestion from @dtcxzyw --- llvm/lib/Analysis/InstructionSimplify.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp index e5d2842a0ae7b..6f44713bd22cd 100644 --- a/llvm/lib/Analysis/InstructionSimplify.cpp +++ b/llvm/lib/Analysis/InstructionSimplify.cpp @@ -6985,12 +6985,12 @@ Value *llvm::simplifyBinaryIntrinsic(Intrinsic::ID IID, Type *ReturnType, // VectorShuffle instruction, which is not allowed in simplifyBinOp. OptResult = MinMaxOptResult::UseEither; for (unsigned i = 0; i != ElemCount.getFixedValue(); ++i) { - if (!C->getAggregateElement(i)) { + auto *Elt = C->getAggregateElement(i); + if (!Elt) { OptResult = MinMaxOptResult::CannotOptimize; break; } - auto ElemResult = OptimizeConstMinMax(C->getAggregateElement(i), - IID, Call, &NewConst); + auto ElemResult = OptimizeConstMinMax(Elt, IID, Call, &NewConst); if (ElemResult == MinMaxOptResult::CannotOptimize || (ElemResult != OptResult && OptResult != MinMaxOptResult::UseEither &&