[llvm] [InstCombine] fix assertion failure in intrinsic distributive laws (PR #216483)

via llvm-commits llvm-commits at lists.llvm.org
Sat Aug 15 10:11:58 PDT 2026


https://github.com/im-lunex updated https://github.com/llvm/llvm-project/pull/216483

>From bb78d0e2214c27df844d87c833967ce326a8c2b9 Mon Sep 17 00:00:00 2001
From: im-lunex <thisissamir04 at gmail.com>
Date: Sat, 15 Aug 2026 17:18:50 +0600
Subject: [PATCH 1/3] fix assertion failure in intrinsic distributive laws

---
 .../InstCombine/InstCombineCalls.cpp          | 16 ++++++++--------
 .../intrinsic-distributive-laws-crash.ll      | 19 +++++++++++++++++++
 2 files changed, 27 insertions(+), 8 deletions(-)
 create mode 100644 llvm/test/Transforms/InstCombine/intrinsic-distributive-laws-crash.ll

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
index 7fee08ad21d28..9d23008131c3b 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
@@ -1853,24 +1853,24 @@ foldIntrinsicUsingDistributiveLaws(IntrinsicInst *II,
       return nullptr;
   }
 
-  BinaryOperator *NewBinop;
+  Value *NewBinop; // dont decide BinaryOperator now
   if (A == C &&
       leftDistributesOverRight(InnerOpcode, HasNUW, HasNSW, TopLevelOpcode)) {
     Value *NewIntrinsic = Builder.CreateBinaryIntrinsic(TopLevelOpcode, B, D);
-    NewBinop =
-        cast<BinaryOperator>(Builder.CreateBinOp(InnerOpcode, A, NewIntrinsic));
+    NewBinop = Builder.CreateBinOp(InnerOpcode, A, NewIntrinsic);
   } else if (B == D && rightDistributesOverLeft(InnerOpcode, HasNUW, HasNSW,
                                                 TopLevelOpcode)) {
     Value *NewIntrinsic = Builder.CreateBinaryIntrinsic(TopLevelOpcode, A, C);
-    NewBinop =
-        cast<BinaryOperator>(Builder.CreateBinOp(InnerOpcode, NewIntrinsic, B));
+    NewBinop = Builder.CreateBinOp(InnerOpcode, NewIntrinsic, B);
   } else {
     return nullptr;
   }
 
-  NewBinop->setHasNoUnsignedWrap(HasNUW);
-  NewBinop->setHasNoSignedWrap(HasNSW);
-
+  // check if NewBinop is actually a BinaryOperator
+  if (BinaryOperator *NBO = dyn_cast<BinaryOperator>(NewBinop)) {
+    NBO->setHasNoUnsignedWrap(HasNUW);
+    NBO->setHasNoSignedWrap(HasNSW);
+  }
   return NewBinop;
 }
 
diff --git a/llvm/test/Transforms/InstCombine/intrinsic-distributive-laws-crash.ll b/llvm/test/Transforms/InstCombine/intrinsic-distributive-laws-crash.ll
new file mode 100644
index 0000000000000..8f9a097825da7
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/intrinsic-distributive-laws-crash.ll
@@ -0,0 +1,19 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -S -passes=instcombine %s | FileCheck %s
+
+declare i32 @llvm.smin.i32(i32, i32)
+
+define i32 @test_intrinsic_distributive_laws_crash(i32 %g, i32 %h, i32 %i) {
+; CHECK-LABEL: @test_intrinsic_distributive_laws_crash(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp slt i32 [[G:%.*]], [[H:%.*]]
+; CHECK-NEXT:    [[INNER_MIN:%.*]] = call i32 @llvm.smin.i32(i32 [[G]], i32 [[I:%.*]])
+; CHECK-NEXT:    [[RESULT:%.*]] = select i1 [[CMP1]], i32 0, i32 [[INNER_MIN]]
+; CHECK-NEXT:    ret i32 [[RESULT]]
+;
+entry:
+  %cmp1 = icmp slt i32 %g, %h
+  %inner_min = call i32 @llvm.smin.i32(i32 %g, i32 %i)
+  %result = select i1 %cmp1, i32 0, i32 %inner_min
+  ret i32 %result
+}

>From b93ba051c27fdcaa4ba92bcc8bcb0ec9f60da0b5 Mon Sep 17 00:00:00 2001
From: im-lunex <thisissamir04 at gmail.com>
Date: Sat, 15 Aug 2026 17:47:27 +0600
Subject: [PATCH 2/3] improve the test

---
 .../intrinsic-distributive-laws-crash.ll      | 23 +++++++++----------
 1 file changed, 11 insertions(+), 12 deletions(-)

diff --git a/llvm/test/Transforms/InstCombine/intrinsic-distributive-laws-crash.ll b/llvm/test/Transforms/InstCombine/intrinsic-distributive-laws-crash.ll
index 8f9a097825da7..b69f6842b06e8 100644
--- a/llvm/test/Transforms/InstCombine/intrinsic-distributive-laws-crash.ll
+++ b/llvm/test/Transforms/InstCombine/intrinsic-distributive-laws-crash.ll
@@ -1,19 +1,18 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
 ; RUN: opt -S -passes=instcombine %s | FileCheck %s
 
+ at g = global i32 0
+
 declare i32 @llvm.smin.i32(i32, i32)
 
-define i32 @test_intrinsic_distributive_laws_crash(i32 %g, i32 %h, i32 %i) {
-; CHECK-LABEL: @test_intrinsic_distributive_laws_crash(
-; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[CMP1:%.*]] = icmp slt i32 [[G:%.*]], [[H:%.*]]
-; CHECK-NEXT:    [[INNER_MIN:%.*]] = call i32 @llvm.smin.i32(i32 [[G]], i32 [[I:%.*]])
-; CHECK-NEXT:    [[RESULT:%.*]] = select i1 [[CMP1]], i32 0, i32 [[INNER_MIN]]
-; CHECK-NEXT:    ret i32 [[RESULT]]
+define i32 @test_constexpr_distributive_crash() {
+; CHECK-LABEL: @test_constexpr_distributive_crash(
+; CHECK-NEXT:    [[RES:%.*]] = call i32 @llvm.smin.i32(i32 add (i32 ptrtoint (ptr @g to i32), i32 10), i32 add (i32 ptrtoint (ptr @g to i32), i32 20))
+; CHECK-NEXT:    ret i32 [[RES]]
 ;
-entry:
-  %cmp1 = icmp slt i32 %g, %h
-  %inner_min = call i32 @llvm.smin.i32(i32 %g, i32 %i)
-  %result = select i1 %cmp1, i32 0, i32 %inner_min
-  ret i32 %result
+  %res = call i32 @llvm.smin.i32(
+  i32 add nsw (i32 ptrtoint (ptr @g to i32), i32 10),
+  i32 add nsw (i32 ptrtoint (ptr @g to i32), i32 20)
+  )
+  ret i32 %res
 }

>From e4c62e9fd8ebe0221d538539eba6148c85ce4ba3 Mon Sep 17 00:00:00 2001
From: im-lunex <thisissamir04 at gmail.com>
Date: Sat, 15 Aug 2026 22:53:02 +0600
Subject: [PATCH 3/3] add test

---
 .../intrinsic-distributive-laws-crash.ll      | 140 +++++++++++++++---
 1 file changed, 123 insertions(+), 17 deletions(-)

diff --git a/llvm/test/Transforms/InstCombine/intrinsic-distributive-laws-crash.ll b/llvm/test/Transforms/InstCombine/intrinsic-distributive-laws-crash.ll
index b69f6842b06e8..e87ac5cf69daa 100644
--- a/llvm/test/Transforms/InstCombine/intrinsic-distributive-laws-crash.ll
+++ b/llvm/test/Transforms/InstCombine/intrinsic-distributive-laws-crash.ll
@@ -1,18 +1,124 @@
-; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt -S -passes=instcombine %s | FileCheck %s
-
- at g = global i32 0
-
-declare i32 @llvm.smin.i32(i32, i32)
-
-define i32 @test_constexpr_distributive_crash() {
-; CHECK-LABEL: @test_constexpr_distributive_crash(
-; CHECK-NEXT:    [[RES:%.*]] = call i32 @llvm.smin.i32(i32 add (i32 ptrtoint (ptr @g to i32), i32 10), i32 add (i32 ptrtoint (ptr @g to i32), i32 20))
-; CHECK-NEXT:    ret i32 [[RES]]
-;
-  %res = call i32 @llvm.smin.i32(
-  i32 add nsw (i32 ptrtoint (ptr @g to i32), i32 10),
-  i32 add nsw (i32 ptrtoint (ptr @g to i32), i32 20)
-  )
-  ret i32 %res
+; RUN: opt -passes='default<O1>' -S %s -o /dev/null
+; REQUIRES: asserts
+; ModuleID = 'repro_0.ll'
+source_filename = "repro.cpp"
+target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+ at c = external global i32
+ at b = external global i8
+
+; Function Attrs: nounwind uwtable
+declare void @d() #0
+
+; Function Attrs: nounwind uwtable
+define i32 @e(i32 noundef %g, i32 noundef %h, i32 noundef %i) #0 {
+entry:
+  %g.addr = alloca i32, align 4
+  %h.addr = alloca i32, align 4
+  %i.addr = alloca i32, align 4
+  %f = alloca i32, align 4
+  store i32 %g, ptr %g.addr, align 4
+  store i32 %h, ptr %h.addr, align 4
+  store i32 %i, ptr %i.addr, align 4
+  %0 = load i32, ptr %g.addr, align 4
+  %1 = load i32, ptr %h.addr, align 4
+  %cmp = icmp slt i32 %0, %1
+  br i1 %cmp, label %cond.true, label %cond.false
+
+cond.true:                                        ; preds = %entry
+  ret i32 0
+
+cond.false:                                       ; preds = %entry
+  %2 = load i32, ptr %g.addr, align 4
+  %3 = load i32, ptr %i.addr, align 4
+  %cmp1 = icmp sgt i32 %2, %3
+  %4 = load i32, ptr %i.addr, align 4
+  %5 = load i32, ptr %g.addr, align 4
+  %cond = select i1 %cmp1, i32 %4, i32 %5
+  br label %cond.end
+
+cond.true2:                                       ; No predecessors!
+  br label %cond.end
+
+cond.false3:                                      ; No predecessors!
+  br label %cond.end
+
+cond.end:                                         ; preds = %cond.false3, %cond.true2, %cond.false
+  store i32 %cond, ptr %f, align 4
+  %6 = load i32, ptr %f, align 4
+  ret i32 %6
 }
+
+; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: readwrite)
+declare void @llvm.lifetime.start.p0(ptr captures(none)) #1
+
+; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: readwrite)
+declare void @llvm.lifetime.end.p0(ptr captures(none)) #1
+
+; Function Attrs: nounwind uwtable
+define void @j() #0 {
+entry:
+  %k = alloca i32, align 4
+  %l = alloca i32, align 4
+  %m = alloca ptr, align 8
+  store i32 893196426, ptr %k, align 4
+  store i32 826450915, ptr %l, align 4
+  br label %do.body
+
+do.body:                                          ; preds = %do.body, %entry
+  store ptr %k, ptr %m, align 8
+  %0 = load i32, ptr %k, align 4
+  %conv = sext i32 %0 to i64
+  %shl = shl i64 %conv, 52
+  %shr = ashr i64 %shl, 52
+  %sub = sub nsw i64 0, %shr
+  %conv1 = trunc i64 %sub to i32
+  %1 = load i32, ptr %k, align 4
+  %conv2 = sext i32 %1 to i64
+  %shl3 = shl i64 %conv2, 32
+  %shr4 = ashr i64 %shl3, 32
+  %shl5 = shl i64 %shr4, 52
+  %shr6 = ashr i64 %shl5, 52
+  %conv7 = trunc i64 %shr6 to i32
+  %add = add nsw i32 2, %conv7
+  %2 = load i32, ptr %k, align 4
+  %conv8 = sext i32 %2 to i64
+  %shl9 = shl i64 %conv8, 32
+  %shr10 = ashr i64 %shl9, 32
+  %shl11 = shl i64 %shr10, 52
+  %shr12 = ashr i64 %shl11, 52
+  %conv13 = trunc i64 %shr12 to i32
+  %sub14 = sub nsw i32 2, %conv13
+  %call = call i32 @e(i32 noundef %conv1, i32 noundef %add, i32 noundef %sub14)
+  store i32 %call, ptr @c, align 4
+  %3 = load i32, ptr %l, align 4
+  store i32 %3, ptr %k, align 4
+  %4 = load ptr, ptr %m, align 8
+  %5 = load i32, ptr %4, align 4
+  %6 = load i8, ptr @b, align 1
+  %conv15 = sext i8 %6 to i32
+  %sub16 = sub nsw i32 %5, %conv15
+  %sub17 = sub nsw i32 %sub16, 7
+  %tobool = icmp ne i32 %sub17, 0
+  %lnot = xor i1 %tobool, true
+  br i1 %lnot, label %do.body, label %do.end
+
+do.end:                                           ; preds = %do.body
+  %7 = load i32, ptr null, align 4
+  %tobool18 = icmp ne i32 %7, 0
+  br i1 %tobool18, label %if.then, label %if.end
+
+if.then:                                          ; preds = %do.end
+  store ptr %l, ptr %m, align 8
+  br label %if.end
+
+if.end:                                           ; preds = %if.then, %do.end
+  call void @d()
+  %8 = load ptr, ptr %m, align 8
+  %9 = load i32, ptr %8, align 4
+  ret void
+}
+
+attributes #0 = { nounwind uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
+attributes #1 = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) }



More information about the llvm-commits mailing list