Skip to content

Commit 126016b

Browse files
authored
[InstCombine] Simplify nonnull pointers (#128111)
This patch is the follow-up of #127979. It introduces a helper `simplifyNonNullOperand` to avoid duplicate logic. It also addresses the one-use issue in `visitLoadInst`, as discussed in #127979 (comment). The `nonnull` attribute is also supported. Proof: https://alive2.llvm.org/ce/z/MCKgT9
1 parent 60f3fdd commit 126016b

File tree

7 files changed

+83
-55
lines changed

7 files changed

+83
-55
lines changed

llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3993,10 +3993,19 @@ Instruction *InstCombinerImpl::visitCallBase(CallBase &Call) {
39933993
unsigned ArgNo = 0;
39943994

39953995
for (Value *V : Call.args()) {
3996-
if (V->getType()->isPointerTy() &&
3997-
!Call.paramHasAttr(ArgNo, Attribute::NonNull) &&
3998-
isKnownNonZero(V, getSimplifyQuery().getWithInstruction(&Call)))
3999-
ArgNos.push_back(ArgNo);
3996+
if (V->getType()->isPointerTy()) {
3997+
// Simplify the nonnull operand if the parameter is known to be nonnull.
3998+
// Otherwise, try to infer nonnull for it.
3999+
if (Call.paramHasNonNullAttr(ArgNo, /*AllowUndefOrPoison=*/true)) {
4000+
if (Value *Res = simplifyNonNullOperand(V)) {
4001+
replaceOperand(Call, ArgNo, Res);
4002+
Changed = true;
4003+
}
4004+
} else if (isKnownNonZero(V,
4005+
getSimplifyQuery().getWithInstruction(&Call))) {
4006+
ArgNos.push_back(ArgNo);
4007+
}
4008+
}
40004009
ArgNo++;
40014010
}
40024011

llvm/lib/Transforms/InstCombine/InstCombineInternal.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -455,6 +455,10 @@ class LLVM_LIBRARY_VISIBILITY InstCombinerImpl final
455455

456456
Instruction *hoistFNegAboveFMulFDiv(Value *FNegOp, Instruction &FMFSource);
457457

458+
/// Simplify \p V given that it is known to be non-null.
459+
/// Returns the simplified value if possible, otherwise returns nullptr.
460+
Value *simplifyNonNullOperand(Value *V);
461+
458462
public:
459463
/// Create and insert the idiom we use to indicate a block is unreachable
460464
/// without having to rewrite the CFG from within InstCombine.

llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp

Lines changed: 21 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -982,6 +982,19 @@ static bool canSimplifyNullLoadOrGEP(LoadInst &LI, Value *Op) {
982982
return false;
983983
}
984984

985+
/// TODO: Recursively simplify nonnull value to handle one-use inbounds GEPs.
986+
Value *InstCombinerImpl::simplifyNonNullOperand(Value *V) {
987+
if (auto *Sel = dyn_cast<SelectInst>(V)) {
988+
if (isa<ConstantPointerNull>(Sel->getOperand(1)))
989+
return Sel->getOperand(2);
990+
991+
if (isa<ConstantPointerNull>(Sel->getOperand(2)))
992+
return Sel->getOperand(1);
993+
}
994+
995+
return nullptr;
996+
}
997+
985998
Instruction *InstCombinerImpl::visitLoadInst(LoadInst &LI) {
986999
Value *Op = LI.getOperand(0);
9871000
if (Value *Res = simplifyLoadInst(&LI, Op, SQ.getWithInstruction(&LI)))
@@ -1059,20 +1072,13 @@ Instruction *InstCombinerImpl::visitLoadInst(LoadInst &LI) {
10591072
V2->copyMetadata(LI, Metadata::PoisonGeneratingIDs);
10601073
return SelectInst::Create(SI->getCondition(), V1, V2);
10611074
}
1062-
1063-
// load (select (cond, null, P)) -> load P
1064-
if (isa<ConstantPointerNull>(SI->getOperand(1)) &&
1065-
!NullPointerIsDefined(SI->getFunction(),
1066-
LI.getPointerAddressSpace()))
1067-
return replaceOperand(LI, 0, SI->getOperand(2));
1068-
1069-
// load (select (cond, P, null)) -> load P
1070-
if (isa<ConstantPointerNull>(SI->getOperand(2)) &&
1071-
!NullPointerIsDefined(SI->getFunction(),
1072-
LI.getPointerAddressSpace()))
1073-
return replaceOperand(LI, 0, SI->getOperand(1));
10741075
}
10751076
}
1077+
1078+
if (!NullPointerIsDefined(LI.getFunction(), LI.getPointerAddressSpace()))
1079+
if (Value *V = simplifyNonNullOperand(Op))
1080+
return replaceOperand(LI, 0, V);
1081+
10761082
return nullptr;
10771083
}
10781084

@@ -1437,19 +1443,9 @@ Instruction *InstCombinerImpl::visitStoreInst(StoreInst &SI) {
14371443
if (isa<UndefValue>(Val))
14381444
return eraseInstFromFunction(SI);
14391445

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-
}
1446+
if (!NullPointerIsDefined(SI.getFunction(), SI.getPointerAddressSpace()))
1447+
if (Value *V = simplifyNonNullOperand(Ptr))
1448+
return replaceOperand(SI, 1, V);
14531449

14541450
return nullptr;
14551451
}

llvm/lib/Transforms/InstCombine/InstructionCombining.cpp

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3587,10 +3587,23 @@ Instruction *InstCombinerImpl::visitFree(CallInst &FI, Value *Op) {
35873587

35883588
Instruction *InstCombinerImpl::visitReturnInst(ReturnInst &RI) {
35893589
Value *RetVal = RI.getReturnValue();
3590-
if (!RetVal || !AttributeFuncs::isNoFPClassCompatibleType(RetVal->getType()))
3590+
if (!RetVal)
35913591
return nullptr;
35923592

35933593
Function *F = RI.getFunction();
3594+
Type *RetTy = RetVal->getType();
3595+
if (RetTy->isPointerTy()) {
3596+
if (F->hasRetAttribute(Attribute::NonNull) ||
3597+
(F->getAttributes().getRetDereferenceableBytes() > 0 &&
3598+
!NullPointerIsDefined(F, RetTy->getPointerAddressSpace()))) {
3599+
if (Value *V = simplifyNonNullOperand(RetVal))
3600+
return replaceOperand(RI, 0, V);
3601+
}
3602+
}
3603+
3604+
if (!AttributeFuncs::isNoFPClassCompatibleType(RetTy))
3605+
return nullptr;
3606+
35943607
FPClassTest ReturnClass = F->getAttributes().getRetNoFPClass();
35953608
if (ReturnClass == fcNone)
35963609
return nullptr;

llvm/test/Transforms/InstCombine/nonnull-select.ll

Lines changed: 9 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,7 @@
55

66
define nonnull ptr @pr48975(ptr %.0) {
77
; CHECK-LABEL: @pr48975(
8-
; CHECK-NEXT: [[DOT1:%.*]] = load ptr, ptr [[DOT0:%.*]], align 8
9-
; CHECK-NEXT: [[DOT2:%.*]] = icmp eq ptr [[DOT1]], null
10-
; CHECK-NEXT: [[DOT4:%.*]] = select i1 [[DOT2]], ptr null, ptr [[DOT0]]
11-
; CHECK-NEXT: ret ptr [[DOT4]]
8+
; CHECK-NEXT: ret ptr [[DOT4:%.*]]
129
;
1310
%.1 = load ptr, ptr %.0, align 8
1411
%.2 = icmp eq ptr %.1, null
@@ -18,35 +15,31 @@ define nonnull ptr @pr48975(ptr %.0) {
1815

1916
define nonnull ptr @nonnull_ret(i1 %cond, ptr %p) {
2017
; CHECK-LABEL: @nonnull_ret(
21-
; CHECK-NEXT: [[RES:%.*]] = select i1 [[COND:%.*]], ptr [[P:%.*]], ptr null
22-
; CHECK-NEXT: ret ptr [[RES]]
18+
; CHECK-NEXT: ret ptr [[RES:%.*]]
2319
;
2420
%res = select i1 %cond, ptr %p, ptr null
2521
ret ptr %res
2622
}
2723

2824
define nonnull ptr @nonnull_ret2(i1 %cond, ptr %p) {
2925
; CHECK-LABEL: @nonnull_ret2(
30-
; CHECK-NEXT: [[RES:%.*]] = select i1 [[COND:%.*]], ptr null, ptr [[P:%.*]]
31-
; CHECK-NEXT: ret ptr [[RES]]
26+
; CHECK-NEXT: ret ptr [[RES:%.*]]
3227
;
3328
%res = select i1 %cond, ptr null, ptr %p
3429
ret ptr %res
3530
}
3631

3732
define nonnull noundef ptr @nonnull_noundef_ret(i1 %cond, ptr %p) {
3833
; CHECK-LABEL: @nonnull_noundef_ret(
39-
; CHECK-NEXT: [[RES:%.*]] = select i1 [[COND:%.*]], ptr [[P:%.*]], ptr null
40-
; CHECK-NEXT: ret ptr [[RES]]
34+
; CHECK-NEXT: ret ptr [[RES:%.*]]
4135
;
4236
%res = select i1 %cond, ptr %p, ptr null
4337
ret ptr %res
4438
}
4539

4640
define nonnull noundef ptr @nonnull_noundef_ret2(i1 %cond, ptr %p) {
4741
; CHECK-LABEL: @nonnull_noundef_ret2(
48-
; CHECK-NEXT: [[RES:%.*]] = select i1 [[COND:%.*]], ptr null, ptr [[P:%.*]]
49-
; CHECK-NEXT: ret ptr [[RES]]
42+
; CHECK-NEXT: ret ptr [[RES:%.*]]
5043
;
5144
%res = select i1 %cond, ptr null, ptr %p
5245
ret ptr %res
@@ -55,8 +48,7 @@ define nonnull noundef ptr @nonnull_noundef_ret2(i1 %cond, ptr %p) {
5548

5649
define void @nonnull_call(i1 %cond, ptr %p) {
5750
; CHECK-LABEL: @nonnull_call(
58-
; CHECK-NEXT: [[RES:%.*]] = select i1 [[COND:%.*]], ptr [[P:%.*]], ptr null
59-
; CHECK-NEXT: call void @f(ptr nonnull [[RES]])
51+
; CHECK-NEXT: call void @f(ptr nonnull [[RES:%.*]])
6052
; CHECK-NEXT: ret void
6153
;
6254
%res = select i1 %cond, ptr %p, ptr null
@@ -66,8 +58,7 @@ define void @nonnull_call(i1 %cond, ptr %p) {
6658

6759
define void @nonnull_call2(i1 %cond, ptr %p) {
6860
; CHECK-LABEL: @nonnull_call2(
69-
; CHECK-NEXT: [[RES:%.*]] = select i1 [[COND:%.*]], ptr null, ptr [[P:%.*]]
70-
; CHECK-NEXT: call void @f(ptr nonnull [[RES]])
61+
; CHECK-NEXT: call void @f(ptr nonnull [[RES:%.*]])
7162
; CHECK-NEXT: ret void
7263
;
7364
%res = select i1 %cond, ptr null, ptr %p
@@ -77,8 +68,7 @@ define void @nonnull_call2(i1 %cond, ptr %p) {
7768

7869
define void @nonnull_noundef_call(i1 %cond, ptr %p) {
7970
; CHECK-LABEL: @nonnull_noundef_call(
80-
; CHECK-NEXT: [[RES:%.*]] = select i1 [[COND:%.*]], ptr [[P:%.*]], ptr null
81-
; CHECK-NEXT: call void @f(ptr noundef nonnull [[RES]])
71+
; CHECK-NEXT: call void @f(ptr noundef nonnull [[RES:%.*]])
8272
; CHECK-NEXT: ret void
8373
;
8474
%res = select i1 %cond, ptr %p, ptr null
@@ -88,8 +78,7 @@ define void @nonnull_noundef_call(i1 %cond, ptr %p) {
8878

8979
define void @nonnull_noundef_call2(i1 %cond, ptr %p) {
9080
; CHECK-LABEL: @nonnull_noundef_call2(
91-
; CHECK-NEXT: [[RES:%.*]] = select i1 [[COND:%.*]], ptr null, ptr [[P:%.*]]
92-
; CHECK-NEXT: call void @f(ptr noundef nonnull [[RES]])
81+
; CHECK-NEXT: call void @f(ptr noundef nonnull [[RES:%.*]])
9382
; CHECK-NEXT: ret void
9483
;
9584
%res = select i1 %cond, ptr null, ptr %p

llvm/test/Transforms/PhaseOrdering/load-store-sameval.ll

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,21 @@
11
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
22
; RUN: opt -passes='instcombine,early-cse<memssa>' -S %s | FileCheck %s
33

4-
; FIXME: We can remove the store instruction in the exit block
54
define i32 @load_store_sameval(ptr %p, i1 %cond1, i1 %cond2) {
65
; CHECK-LABEL: define i32 @load_store_sameval(
76
; CHECK-SAME: ptr [[P:%.*]], i1 [[COND1:%.*]], i1 [[COND2:%.*]]) {
87
; 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
8+
; CHECK-NEXT: [[PRE:%.*]] = load i32, ptr [[P]], align 4
119
; CHECK-NEXT: br label %[[BLOCK:.*]]
1210
; CHECK: [[BLOCK]]:
1311
; CHECK-NEXT: br label %[[BLOCK2:.*]]
1412
; CHECK: [[BLOCK2]]:
1513
; CHECK-NEXT: br i1 [[COND2]], label %[[BLOCK3:.*]], label %[[EXIT:.*]]
1614
; CHECK: [[BLOCK3]]:
17-
; CHECK-NEXT: [[LOAD:%.*]] = load double, ptr [[SPEC_SELECT]], align 8
15+
; CHECK-NEXT: [[LOAD:%.*]] = load double, ptr [[P]], align 8
1816
; CHECK-NEXT: [[CMP:%.*]] = fcmp une double [[LOAD]], 0.000000e+00
1917
; CHECK-NEXT: br i1 [[CMP]], label %[[BLOCK]], label %[[BLOCK2]]
2018
; CHECK: [[EXIT]]:
21-
; CHECK-NEXT: store i32 [[PRE]], ptr [[P]], align 4
2219
; CHECK-NEXT: ret i32 0
2320
;
2421
entry:
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
2+
3+
; RUN: opt < %s -passes=instcombine,memcpyopt -S | FileCheck %s
4+
5+
; FIXME: These two memset calls should be merged into a single one.
6+
define void @merge_memset(ptr %p, i1 %cond) {
7+
; CHECK-LABEL: define void @merge_memset(
8+
; CHECK-SAME: ptr [[P:%.*]], i1 [[COND:%.*]]) {
9+
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[COND]], ptr null, ptr [[P]]
10+
; CHECK-NEXT: tail call void @llvm.memset.p0.i64(ptr noundef nonnull align 1 dereferenceable(4096) [[P]], i8 0, i64 4096, i1 false)
11+
; CHECK-NEXT: [[OFF:%.*]] = getelementptr inbounds nuw i8, ptr [[SEL]], i64 4096
12+
; CHECK-NEXT: tail call void @llvm.memset.p0.i64(ptr noundef nonnull align 1 dereferenceable(768) [[OFF]], i8 0, i64 768, i1 false)
13+
; CHECK-NEXT: ret void
14+
;
15+
%sel = select i1 %cond, ptr null, ptr %p
16+
tail call void @llvm.memset.p0.i64(ptr noundef nonnull %sel, i8 0, i64 4096, i1 false)
17+
%off = getelementptr inbounds nuw i8, ptr %sel, i64 4096
18+
tail call void @llvm.memset.p0.i64(ptr noundef nonnull %off, i8 0, i64 768, i1 false)
19+
ret void
20+
}

0 commit comments

Comments
 (0)