Skip to content

Commit

Permalink
Reland "[SimplifyCFG] Improve the precision of PtrValueMayBeModified"
Browse files Browse the repository at this point in the history
This relands commit f890f01.

The result value of `getelementptr inbounds (TY, null, not zero)` is a poison value.
We can think of it as undefined behavior.
  • Loading branch information
DianQK committed Jan 24, 2024
1 parent a0c1b5b commit a58dcc5
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 4 deletions.
11 changes: 10 additions & 1 deletion llvm/lib/Transforms/Utils/SimplifyCFG.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7395,7 +7395,16 @@ static bool passingValueIsAlwaysUndefined(Value *V, Instruction *I, bool PtrValu
// Look through GEPs. A load from a GEP derived from NULL is still undefined
if (GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(Use))
if (GEP->getPointerOperand() == I) {
if (!GEP->isInBounds() || !GEP->hasAllZeroIndices())
// The current base address is null, there are four cases to consider:
// getelementptr (TY, null, 0) -> null
// getelementptr (TY, null, not zero) -> may be modified
// getelementptr inbounds (TY, null, 0) -> null
// getelementptr inbounds (TY, null, not zero) -> poison iff null is
// undefined?
if (!GEP->hasAllZeroIndices() &&
(!GEP->isInBounds() ||
NullPointerIsDefined(GEP->getFunction(),
GEP->getPointerAddressSpace())))
PtrValueMayBeModified = true;
return passingValueIsAlwaysUndefined(V, GEP, PtrValueMayBeModified);
}
Expand Down
68 changes: 66 additions & 2 deletions llvm/test/Transforms/SimplifyCFG/UnreachableEliminate.ll
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,28 @@ else:
define void @test9_gep_inbounds_nonzero(i1 %X, ptr %Y) {
; CHECK-LABEL: @test9_gep_inbounds_nonzero(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TMP0:%.*]] = xor i1 [[X:%.*]], true
; CHECK-NEXT: call void @llvm.assume(i1 [[TMP0]])
; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, ptr [[Y:%.*]], i64 12
; CHECK-NEXT: [[TMP1:%.*]] = call ptr @fn_nonnull_noundef_arg(ptr [[GEP]])
; CHECK-NEXT: ret void
;
entry:
br i1 %X, label %if, label %else

if:
br label %else

else:
%phi = phi ptr [ %Y, %entry ], [ null, %if ]
%gep = getelementptr inbounds i8, ptr %phi, i64 12
call ptr @fn_nonnull_noundef_arg(ptr %gep)
ret void
}

define void @test9_gep_inbounds_nonzero_null_defined(i1 %X, ptr %Y) #0 {
; CHECK-LABEL: @test9_gep_inbounds_nonzero_null_defined(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[SPEC_SELECT:%.*]] = select i1 [[X:%.*]], ptr null, ptr [[Y:%.*]]
; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, ptr [[SPEC_SELECT]], i64 12
; CHECK-NEXT: [[TMP0:%.*]] = call ptr @fn_nonnull_noundef_arg(ptr [[GEP]])
Expand All @@ -462,9 +484,30 @@ else:
ret void
}

define void @test9_gep_inbounds_unknown_null(i1 %X, ptr %Y, i64 %I) {
; CHECK-LABEL: @test9_gep_inbounds_unknown_null(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TMP0:%.*]] = xor i1 [[X:%.*]], true
; CHECK-NEXT: call void @llvm.assume(i1 [[TMP0]])
; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, ptr [[Y:%.*]], i64 [[I:%.*]]
; CHECK-NEXT: [[TMP1:%.*]] = call ptr @fn_nonnull_noundef_arg(ptr [[GEP]])
; CHECK-NEXT: ret void
;
entry:
br i1 %X, label %if, label %else

if:
br label %else

else:
%phi = phi ptr [ %Y, %entry ], [ null, %if ]
%gep = getelementptr inbounds i8, ptr %phi, i64 %I
call ptr @fn_nonnull_noundef_arg(ptr %gep)
ret void
}

define void @test9_gep_inbouds_unknown_null(i1 %X, ptr %Y, i64 %I) {
; CHECK-LABEL: @test9_gep_inbouds_unknown_null(
define void @test9_gep_inbounds_unknown_null_defined(i1 %X, ptr %Y, i64 %I) #0 {
; CHECK-LABEL: @test9_gep_inbounds_unknown_null_defined(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[SPEC_SELECT:%.*]] = select i1 [[X:%.*]], ptr null, ptr [[Y:%.*]]
; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, ptr [[SPEC_SELECT]], i64 [[I:%.*]]
Expand All @@ -484,6 +527,27 @@ else:
ret void
}

define void @test9_gep_inbounds_unknown_null_call_noundef(i1 %X, ptr %Y, i64 %I) {
; CHECK-LABEL: @test9_gep_inbounds_unknown_null_call_noundef(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[SPEC_SELECT:%.*]] = select i1 [[X:%.*]], ptr null, ptr [[Y:%.*]]
; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, ptr [[SPEC_SELECT]], i64 [[I:%.*]]
; CHECK-NEXT: [[TMP0:%.*]] = call ptr @fn_noundef_arg(ptr [[GEP]])
; CHECK-NEXT: ret void
;
entry:
br i1 %X, label %if, label %else

if:
br label %else

else:
%phi = phi ptr [ %Y, %entry ], [ null, %if ]
%gep = getelementptr inbounds i8, ptr %phi, i64 %I
call ptr @fn_noundef_arg(ptr %gep)
ret void
}

define void @test9_gep_unknown_null(i1 %X, ptr %Y, i64 %I) {
; CHECK-LABEL: @test9_gep_unknown_null(
; CHECK-NEXT: entry:
Expand Down
21 changes: 20 additions & 1 deletion llvm/test/Transforms/SimplifyCFG/unreachable-eliminate-on-ret.ll
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,26 @@ define nonnull noundef ptr @test_ret_ptr_nonnull_noundef_gep_nonzero(i1 %cond, p
; CHECK-LABEL: @test_ret_ptr_nonnull_noundef_gep_nonzero(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[SPEC_SELECT:%.*]] = select i1 [[COND:%.*]], ptr [[X:%.*]], ptr null
; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds ptr, ptr [[SPEC_SELECT]], i64 12
; CHECK-NEXT: [[GEP:%.*]] = getelementptr ptr, ptr [[SPEC_SELECT]], i64 12
; CHECK-NEXT: ret ptr [[GEP]]
;
entry:
br i1 %cond, label %bb1, label %bb2

bb1:
br label %bb2

bb2:
%phi = phi ptr [ null, %entry ], [ %x, %bb1 ]
%gep = getelementptr ptr, ptr %phi, i64 12
ret ptr %gep
}

define nonnull noundef ptr @test_ret_ptr_nonnull_noundef_gep_inbounds_nonzero(i1 %cond, ptr %x) {
; CHECK-LABEL: @test_ret_ptr_nonnull_noundef_gep_inbounds_nonzero(
; CHECK-NEXT: entry:
; CHECK-NEXT: call void @llvm.assume(i1 [[COND:%.*]])
; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds ptr, ptr [[X:%.*]], i64 12
; CHECK-NEXT: ret ptr [[GEP]]
;
entry:
Expand Down

0 comments on commit a58dcc5

Please sign in to comment.