[llvm] [InstCombine] Drop UB-implying attrs/metadata after speculating an instruction (PR #85542)

Yingwei Zheng via llvm-commits llvm-commits at lists.llvm.org
Sat Mar 16 09:51:33 PDT 2024


https://github.com/dtcxzyw created https://github.com/llvm/llvm-project/pull/85542

When speculating an instruction in `InstCombinerImpl::FoldOpIntoSelect`, the call may result in undefined behavior. This patch drops all UB-implying attrs/metadata to fix this.

Fixes #85536.


>From f909799fc87f3d96a0d35207cfc5c49804ac0bfb Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Sun, 17 Mar 2024 00:34:27 +0800
Subject: [PATCH 1/2] [InstCombine] Add pre-commit tests for PR85536. NFC.

---
 llvm/test/Transforms/InstCombine/pr85536.ll | 44 +++++++++++++++++++++
 1 file changed, 44 insertions(+)
 create mode 100644 llvm/test/Transforms/InstCombine/pr85536.ll

diff --git a/llvm/test/Transforms/InstCombine/pr85536.ll b/llvm/test/Transforms/InstCombine/pr85536.ll
new file mode 100644
index 00000000000000..f7369d913e38f6
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/pr85536.ll
@@ -0,0 +1,44 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 4
+; RUN: opt -S -passes=instcombine < %s | FileCheck %s
+
+define i8 @test_drop_noundef(i1 %cond, i8 %val) {
+; CHECK-LABEL: define i8 @test_drop_noundef(
+; CHECK-SAME: i1 [[COND:%.*]], i8 [[VAL:%.*]]) {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[TMP0:%.*]] = call noundef i8 @llvm.smin.i8(i8 [[VAL]], i8 0)
+; CHECK-NEXT:    [[RET:%.*]] = select i1 [[COND]], i8 -1, i8 [[TMP0]]
+; CHECK-NEXT:    ret i8 [[RET]]
+;
+entry:
+  %sel = select i1 %cond, i8 -1, i8 %val
+  %ret = call noundef i8 @llvm.smin.i8(i8 %sel, i8 0)
+  ret i8 %ret
+}
+
+define i1 @pr85536(i32 %a) {
+; CHECK-LABEL: define i1 @pr85536(
+; CHECK-SAME: i32 [[A:%.*]]) {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ult i32 [[A]], 31
+; CHECK-NEXT:    [[SHL1:%.*]] = shl nsw i32 -1, [[A]]
+; CHECK-NEXT:    [[ZEXT:%.*]] = zext i32 [[SHL1]] to i64
+; CHECK-NEXT:    [[SHL2:%.*]] = shl i64 [[ZEXT]], 48
+; CHECK-NEXT:    [[SHR:%.*]] = ashr exact i64 [[SHL2]], 48
+; CHECK-NEXT:    [[TMP0:%.*]] = call noundef i64 @llvm.smin.i64(i64 [[SHR]], i64 0)
+; CHECK-NEXT:    [[TMP1:%.*]] = and i64 [[TMP0]], 65535
+; CHECK-NEXT:    [[RET1:%.*]] = icmp eq i64 [[TMP1]], 0
+; CHECK-NEXT:    [[RET:%.*]] = and i1 [[CMP1]], [[RET1]]
+; CHECK-NEXT:    ret i1 [[RET]]
+;
+entry:
+  %cmp1 = icmp ugt i32 %a, 30
+  %shl1 = shl nsw i32 -1, %a
+  %zext = zext i32 %shl1 to i64
+  %shl2 = shl i64 %zext, 48
+  %shr = ashr exact i64 %shl2, 48
+  %sel = select i1 %cmp1, i64 -1, i64 %shr
+  %smin = call noundef i64 @llvm.smin.i64(i64 %sel, i64 0)
+  %masked = and i64 %smin, 65535
+  %ret = icmp eq i64 %masked, 0
+  ret i1 %ret
+}

>From cccd56e6d6862ee364732dd7a9e2762301ae142c Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Sun, 17 Mar 2024 00:35:55 +0800
Subject: [PATCH 2/2] [InstCombine] Drop ub-implying attrs and metadata after
 speculating an instruction

---
 llvm/lib/Transforms/InstCombine/InstructionCombining.cpp | 7 +++++++
 llvm/test/Transforms/InstCombine/pr85536.ll              | 6 +++---
 2 files changed, 10 insertions(+), 3 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
index edb046defbc1ca..3376653f48a5ca 100644
--- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
@@ -1650,6 +1650,13 @@ static Value *foldOperationIntoSelectOperand(Instruction &I, SelectInst *SI,
                                              Value *NewOp, InstCombiner &IC) {
   Instruction *Clone = I.clone();
   Clone->replaceUsesOfWith(SI, NewOp);
+
+  // If we speculated an instruction, we need to drop any metadata that may
+  // result in undefined behavior, as the metadata might have been valid
+  // only given the branch precondition.
+  // Similarly strip attributes on call parameters that may cause UB in
+  // location the call is moved to.
+  Clone->dropUBImplyingAttrsAndMetadata();
   IC.InsertNewInstBefore(Clone, SI->getIterator());
   return Clone;
 }
diff --git a/llvm/test/Transforms/InstCombine/pr85536.ll b/llvm/test/Transforms/InstCombine/pr85536.ll
index f7369d913e38f6..5e2bab984f9f2b 100644
--- a/llvm/test/Transforms/InstCombine/pr85536.ll
+++ b/llvm/test/Transforms/InstCombine/pr85536.ll
@@ -5,7 +5,7 @@ define i8 @test_drop_noundef(i1 %cond, i8 %val) {
 ; CHECK-LABEL: define i8 @test_drop_noundef(
 ; CHECK-SAME: i1 [[COND:%.*]], i8 [[VAL:%.*]]) {
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[TMP0:%.*]] = call noundef i8 @llvm.smin.i8(i8 [[VAL]], i8 0)
+; CHECK-NEXT:    [[TMP0:%.*]] = call i8 @llvm.smin.i8(i8 [[VAL]], i8 0)
 ; CHECK-NEXT:    [[RET:%.*]] = select i1 [[COND]], i8 -1, i8 [[TMP0]]
 ; CHECK-NEXT:    ret i8 [[RET]]
 ;
@@ -24,10 +24,10 @@ define i1 @pr85536(i32 %a) {
 ; CHECK-NEXT:    [[ZEXT:%.*]] = zext i32 [[SHL1]] to i64
 ; CHECK-NEXT:    [[SHL2:%.*]] = shl i64 [[ZEXT]], 48
 ; CHECK-NEXT:    [[SHR:%.*]] = ashr exact i64 [[SHL2]], 48
-; CHECK-NEXT:    [[TMP0:%.*]] = call noundef i64 @llvm.smin.i64(i64 [[SHR]], i64 0)
+; CHECK-NEXT:    [[TMP0:%.*]] = call i64 @llvm.smin.i64(i64 [[SHR]], i64 0)
 ; CHECK-NEXT:    [[TMP1:%.*]] = and i64 [[TMP0]], 65535
 ; CHECK-NEXT:    [[RET1:%.*]] = icmp eq i64 [[TMP1]], 0
-; CHECK-NEXT:    [[RET:%.*]] = and i1 [[CMP1]], [[RET1]]
+; CHECK-NEXT:    [[RET:%.*]] = select i1 [[CMP1]], i1 [[RET1]], i1 false
 ; CHECK-NEXT:    ret i1 [[RET]]
 ;
 entry:



More information about the llvm-commits mailing list