Skip to content

Commit 1b78ff6

Browse files
authored
[InstCombine] Simplify the pointer operand of store if writing to null is UB (#127979)
Proof: https://alive2.llvm.org/ce/z/mzVj-u I will add some follow-up patches to avoid duplicate code, support more memory instructions, and bypass gep instructions.
1 parent 43f2968 commit 1b78ff6

File tree

3 files changed

+100
-0
lines changed

3 files changed

+100
-0
lines changed

llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1437,6 +1437,20 @@ Instruction *InstCombinerImpl::visitStoreInst(StoreInst &SI) {
14371437
if (isa<UndefValue>(Val))
14381438
return eraseInstFromFunction(SI);
14391439

1440+
// TODO: Add a helper to simplify the pointer operand for all memory
1441+
// instructions.
1442+
// store val, (select (cond, null, P)) -> store val, P
1443+
// store val, (select (cond, P, null)) -> store val, P
1444+
if (!NullPointerIsDefined(SI.getFunction(), SI.getPointerAddressSpace())) {
1445+
if (SelectInst *Sel = dyn_cast<SelectInst>(Ptr)) {
1446+
if (isa<ConstantPointerNull>(Sel->getOperand(1)))
1447+
return replaceOperand(SI, 1, Sel->getOperand(2));
1448+
1449+
if (isa<ConstantPointerNull>(Sel->getOperand(2)))
1450+
return replaceOperand(SI, 1, Sel->getOperand(1));
1451+
}
1452+
}
1453+
14401454
return nullptr;
14411455
}
14421456

llvm/test/Transforms/InstCombine/store.ll

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,48 @@ define void @store_to_readonly_noalias(ptr readonly noalias %0) {
345345
ret void
346346
}
347347

348+
define void @store_select_with_null(i1 %cond, ptr %p) {
349+
; CHECK-LABEL: @store_select_with_null(
350+
; CHECK-NEXT: store i32 0, ptr [[SEL:%.*]], align 4
351+
; CHECK-NEXT: ret void
352+
;
353+
%sel = select i1 %cond, ptr %p, ptr null
354+
store i32 0, ptr %sel, align 4
355+
ret void
356+
}
357+
358+
define void @store_select_with_null_commuted(i1 %cond, ptr %p) {
359+
; CHECK-LABEL: @store_select_with_null_commuted(
360+
; CHECK-NEXT: store i32 0, ptr [[SEL:%.*]], align 4
361+
; CHECK-NEXT: ret void
362+
;
363+
%sel = select i1 %cond, ptr null, ptr %p
364+
store i32 0, ptr %sel, align 4
365+
ret void
366+
}
367+
368+
define void @store_select_with_null_null_is_valid(i1 %cond, ptr %p) null_pointer_is_valid {
369+
; CHECK-LABEL: @store_select_with_null_null_is_valid(
370+
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[COND:%.*]], ptr [[P:%.*]], ptr null
371+
; CHECK-NEXT: store i32 0, ptr [[SEL]], align 4
372+
; CHECK-NEXT: ret void
373+
;
374+
%sel = select i1 %cond, ptr %p, ptr null
375+
store i32 0, ptr %sel, align 4
376+
ret void
377+
}
378+
379+
define void @store_select_with_unknown(i1 %cond, ptr %p, ptr %p2) {
380+
; CHECK-LABEL: @store_select_with_unknown(
381+
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[COND:%.*]], ptr [[P:%.*]], ptr [[P2:%.*]]
382+
; CHECK-NEXT: store i32 0, ptr [[SEL]], align 4
383+
; CHECK-NEXT: ret void
384+
;
385+
%sel = select i1 %cond, ptr %p, ptr %p2
386+
store i32 0, ptr %sel, align 4
387+
ret void
388+
}
389+
348390
!0 = !{!4, !4, i64 0}
349391
!1 = !{!"omnipotent char", !2}
350392
!2 = !{!"Simple C/C++ TBAA"}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
2+
; RUN: opt -passes='instcombine,early-cse<memssa>' -S %s | FileCheck %s
3+
4+
; FIXME: We can remove the store instruction in the exit block
5+
define i32 @load_store_sameval(ptr %p, i1 %cond1, i1 %cond2) {
6+
; CHECK-LABEL: define i32 @load_store_sameval(
7+
; CHECK-SAME: ptr [[P:%.*]], i1 [[COND1:%.*]], i1 [[COND2:%.*]]) {
8+
; CHECK-NEXT: [[ENTRY:.*:]]
9+
; CHECK-NEXT: [[SPEC_SELECT:%.*]] = select i1 [[COND1]], ptr null, ptr [[P]]
10+
; CHECK-NEXT: [[PRE:%.*]] = load i32, ptr [[SPEC_SELECT]], align 4
11+
; CHECK-NEXT: br label %[[BLOCK:.*]]
12+
; CHECK: [[BLOCK]]:
13+
; CHECK-NEXT: br label %[[BLOCK2:.*]]
14+
; CHECK: [[BLOCK2]]:
15+
; CHECK-NEXT: br i1 [[COND2]], label %[[BLOCK3:.*]], label %[[EXIT:.*]]
16+
; CHECK: [[BLOCK3]]:
17+
; CHECK-NEXT: [[LOAD:%.*]] = load double, ptr [[SPEC_SELECT]], align 8
18+
; CHECK-NEXT: [[CMP:%.*]] = fcmp une double [[LOAD]], 0.000000e+00
19+
; CHECK-NEXT: br i1 [[CMP]], label %[[BLOCK]], label %[[BLOCK2]]
20+
; CHECK: [[EXIT]]:
21+
; CHECK-NEXT: store i32 [[PRE]], ptr [[P]], align 4
22+
; CHECK-NEXT: ret i32 0
23+
;
24+
entry:
25+
%spec.select = select i1 %cond1, ptr null, ptr %p
26+
%pre = load i32, ptr %spec.select, align 4
27+
br label %block
28+
29+
block:
30+
br label %block2
31+
32+
block2:
33+
br i1 %cond2, label %block3, label %exit
34+
35+
block3:
36+
%load = load double, ptr %spec.select, align 8
37+
%cmp = fcmp une double %load, 0.000000e+00
38+
br i1 %cmp, label %block, label %block2
39+
40+
exit:
41+
store i32 %pre, ptr %spec.select, align 4
42+
ret i32 0
43+
}
44+

0 commit comments

Comments
 (0)