mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-02-01 05:01:59 +01:00
[InstCombine] Simplify @llvm.usub.with.overflow+non-zero check (PR43251)
Summary: This is again motivated by D67122 sanitizer check enhancement. That patch seemingly worsens `-fsanitize=pointer-overflow` overhead from 25% to 50%, which strongly implies missing folds. In this particular case, given ``` char* test(char& base, unsigned long offset) { return &base - offset; } ``` it will end up producing something like https://godbolt.org/z/luGEju which after optimizations reduces down to roughly ``` declare void @use64(i64) define i1 @test(i8* dereferenceable(1) %base, i64 %offset) { %base_int = ptrtoint i8* %base to i64 %adjusted = sub i64 %base_int, %offset call void @use64(i64 %adjusted) %not_null = icmp ne i64 %adjusted, 0 %no_underflow = icmp ule i64 %adjusted, %base_int %no_underflow_and_not_null = and i1 %not_null, %no_underflow ret i1 %no_underflow_and_not_null } ``` Without D67122 there was no `%not_null`, and in this particular case we can "get rid of it", by merging two checks: Here we are checking: `Base u>= Offset && (Base u- Offset) != 0`, but that is simply `Base u> Offset` Alive proofs: https://rise4fun.com/Alive/QOs The `@llvm.usub.with.overflow` pattern itself is not handled here because this is the main pattern, that we currently consider canonical. https://bugs.llvm.org/show_bug.cgi?id=43251 Reviewers: spatel, nikic, xbolva00, majnemer Reviewed By: xbolva00, majnemer Subscribers: vsk, majnemer, xbolva00, hiraditya, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D67356 llvm-svn: 372341
This commit is contained in:
parent
e15136d802
commit
472f610901
@ -1084,6 +1084,27 @@ static Value *foldUnsignedUnderflowCheck(ICmpInst *ZeroICmp,
|
||||
return Builder.CreateICmpULE(Base, Offset);
|
||||
}
|
||||
|
||||
if (!match(UnsignedICmp,
|
||||
m_c_ICmp(UnsignedPred, m_Specific(Base), m_Specific(Offset))) ||
|
||||
!ICmpInst::isUnsigned(UnsignedPred))
|
||||
return nullptr;
|
||||
if (UnsignedICmp->getOperand(0) != Base)
|
||||
UnsignedPred = ICmpInst::getSwappedPredicate(UnsignedPred);
|
||||
|
||||
// Base >=/> Offset && (Base - Offset) != 0 <--> Base > Offset
|
||||
// (no overflow and not null)
|
||||
if ((UnsignedPred == ICmpInst::ICMP_UGE ||
|
||||
UnsignedPred == ICmpInst::ICMP_UGT) &&
|
||||
EqPred == ICmpInst::ICMP_NE && IsAnd)
|
||||
return Builder.CreateICmpUGT(Base, Offset);
|
||||
|
||||
// Base <=/< Offset || (Base - Offset) == 0 <--> Base <= Offset
|
||||
// (overflow or null)
|
||||
if ((UnsignedPred == ICmpInst::ICMP_ULE ||
|
||||
UnsignedPred == ICmpInst::ICMP_ULT) &&
|
||||
EqPred == ICmpInst::ICMP_EQ && !IsAnd)
|
||||
return Builder.CreateICmpULE(Base, Offset);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -24,8 +24,8 @@ define i1 @t0_noncanonical_ignoreme(i8 %base, i8 %offset) {
|
||||
; CHECK-NEXT: call void @use1(i1 [[NO_UNDERFLOW]])
|
||||
; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp ne i8 [[ADJUSTED]], 0
|
||||
; CHECK-NEXT: call void @use1(i1 [[NOT_NULL]])
|
||||
; CHECK-NEXT: [[R:%.*]] = and i1 [[NOT_NULL]], [[NO_UNDERFLOW]]
|
||||
; CHECK-NEXT: ret i1 [[R]]
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = icmp ugt i8 [[BASE]], [[OFFSET]]
|
||||
; CHECK-NEXT: ret i1 [[TMP1]]
|
||||
;
|
||||
%adjusted = sub i8 %base, %offset
|
||||
call void @use8(i8 %adjusted)
|
||||
@ -45,8 +45,8 @@ define i1 @t1(i8 %base, i8 %offset) {
|
||||
; CHECK-NEXT: call void @use1(i1 [[NO_UNDERFLOW]])
|
||||
; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp ne i8 [[ADJUSTED]], 0
|
||||
; CHECK-NEXT: call void @use1(i1 [[NOT_NULL]])
|
||||
; CHECK-NEXT: [[R:%.*]] = and i1 [[NOT_NULL]], [[NO_UNDERFLOW]]
|
||||
; CHECK-NEXT: ret i1 [[R]]
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = icmp ugt i8 [[BASE]], [[OFFSET]]
|
||||
; CHECK-NEXT: ret i1 [[TMP1]]
|
||||
;
|
||||
%adjusted = sub i8 %base, %offset
|
||||
call void @use8(i8 %adjusted)
|
||||
@ -65,8 +65,8 @@ define i1 @t1_strict(i8 %base, i8 %offset) {
|
||||
; CHECK-NEXT: call void @use1(i1 [[NO_UNDERFLOW]])
|
||||
; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp ne i8 [[ADJUSTED]], 0
|
||||
; CHECK-NEXT: call void @use1(i1 [[NOT_NULL]])
|
||||
; CHECK-NEXT: [[R:%.*]] = and i1 [[NOT_NULL]], [[NO_UNDERFLOW]]
|
||||
; CHECK-NEXT: ret i1 [[R]]
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = icmp ugt i8 [[BASE]], [[OFFSET]]
|
||||
; CHECK-NEXT: ret i1 [[TMP1]]
|
||||
;
|
||||
%adjusted = sub i8 %base, %offset
|
||||
call void @use8(i8 %adjusted)
|
||||
@ -115,8 +115,8 @@ define i1 @t3_commutability0(i8 %base, i8 %offset) {
|
||||
; CHECK-NEXT: call void @use1(i1 [[NO_UNDERFLOW]])
|
||||
; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp ne i8 [[ADJUSTED]], 0
|
||||
; CHECK-NEXT: call void @use1(i1 [[NOT_NULL]])
|
||||
; CHECK-NEXT: [[R:%.*]] = and i1 [[NOT_NULL]], [[NO_UNDERFLOW]]
|
||||
; CHECK-NEXT: ret i1 [[R]]
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = icmp ugt i8 [[BASE]], [[OFFSET]]
|
||||
; CHECK-NEXT: ret i1 [[TMP1]]
|
||||
;
|
||||
%adjusted = sub i8 %base, %offset
|
||||
call void @use8(i8 %adjusted)
|
||||
@ -135,8 +135,8 @@ define i1 @t4_commutability1(i8 %base, i8 %offset) {
|
||||
; CHECK-NEXT: call void @use1(i1 [[NO_UNDERFLOW]])
|
||||
; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp ne i8 [[ADJUSTED]], 0
|
||||
; CHECK-NEXT: call void @use1(i1 [[NOT_NULL]])
|
||||
; CHECK-NEXT: [[R:%.*]] = and i1 [[NO_UNDERFLOW]], [[NOT_NULL]]
|
||||
; CHECK-NEXT: ret i1 [[R]]
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = icmp ugt i8 [[BASE]], [[OFFSET]]
|
||||
; CHECK-NEXT: ret i1 [[TMP1]]
|
||||
;
|
||||
%adjusted = sub i8 %base, %offset
|
||||
call void @use8(i8 %adjusted)
|
||||
@ -155,8 +155,8 @@ define i1 @t5_commutability2(i8 %base, i8 %offset) {
|
||||
; CHECK-NEXT: call void @use1(i1 [[NO_UNDERFLOW]])
|
||||
; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp ne i8 [[ADJUSTED]], 0
|
||||
; CHECK-NEXT: call void @use1(i1 [[NOT_NULL]])
|
||||
; CHECK-NEXT: [[R:%.*]] = and i1 [[NO_UNDERFLOW]], [[NOT_NULL]]
|
||||
; CHECK-NEXT: ret i1 [[R]]
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = icmp ugt i8 [[BASE]], [[OFFSET]]
|
||||
; CHECK-NEXT: ret i1 [[TMP1]]
|
||||
;
|
||||
%adjusted = sub i8 %base, %offset
|
||||
call void @use8(i8 %adjusted)
|
||||
@ -206,8 +206,8 @@ define i1 @t7(i8 %base, i8 %offset) {
|
||||
; CHECK-NEXT: call void @use1(i1 [[UNDERFLOW]])
|
||||
; CHECK-NEXT: [[NULL:%.*]] = icmp eq i8 [[ADJUSTED]], 0
|
||||
; CHECK-NEXT: call void @use1(i1 [[NULL]])
|
||||
; CHECK-NEXT: [[R:%.*]] = or i1 [[NULL]], [[UNDERFLOW]]
|
||||
; CHECK-NEXT: ret i1 [[R]]
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = icmp ule i8 [[BASE]], [[OFFSET]]
|
||||
; CHECK-NEXT: ret i1 [[TMP1]]
|
||||
;
|
||||
%adjusted = sub i8 %base, %offset
|
||||
call void @use8(i8 %adjusted)
|
||||
@ -226,8 +226,8 @@ define i1 @t7_nonstrict(i8 %base, i8 %offset) {
|
||||
; CHECK-NEXT: call void @use1(i1 [[UNDERFLOW]])
|
||||
; CHECK-NEXT: [[NULL:%.*]] = icmp eq i8 [[ADJUSTED]], 0
|
||||
; CHECK-NEXT: call void @use1(i1 [[NULL]])
|
||||
; CHECK-NEXT: [[R:%.*]] = or i1 [[NULL]], [[UNDERFLOW]]
|
||||
; CHECK-NEXT: ret i1 [[R]]
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = icmp ule i8 [[BASE]], [[OFFSET]]
|
||||
; CHECK-NEXT: ret i1 [[TMP1]]
|
||||
;
|
||||
%adjusted = sub i8 %base, %offset
|
||||
call void @use8(i8 %adjusted)
|
||||
@ -272,8 +272,8 @@ define i1 @t9_commutative(i8 %base, i8 %offset) {
|
||||
; CHECK-NEXT: call void @use1(i1 [[UNDERFLOW]])
|
||||
; CHECK-NEXT: [[NULL:%.*]] = icmp eq i8 [[ADJUSTED]], 0
|
||||
; CHECK-NEXT: call void @use1(i1 [[NULL]])
|
||||
; CHECK-NEXT: [[R:%.*]] = or i1 [[NULL]], [[UNDERFLOW]]
|
||||
; CHECK-NEXT: ret i1 [[R]]
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = icmp ule i8 [[BASE]], [[OFFSET]]
|
||||
; CHECK-NEXT: ret i1 [[TMP1]]
|
||||
;
|
||||
%adjusted = sub i8 %base, %offset
|
||||
call void @use8(i8 %adjusted)
|
||||
|
Loading…
x
Reference in New Issue
Block a user