Reland "[SimplifyCFG] Improve the precision of PtrValueMayBeModified"
This relands commit f890f010f6.
The result value of `getelementptr inbounds (TY, null, not zero)` is a poison value.
We can think of it as undefined behavior.
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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]])
|
||||
@@ -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
|
||||
|
||||
define void @test9_gep_inbouds_unknown_null(i1 %X, ptr %Y, i64 %I) {
|
||||
; CHECK-LABEL: @test9_gep_inbouds_unknown_null(
|
||||
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_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:%.*]]
|
||||
@@ -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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user