From: Roman Lebedev Date: Fri, 18 Oct 2019 19:32:47 +0000 (+0000) Subject: [CVP] After proving that @llvm.with.overflow()/@llvm.sat() don't overflow, also try... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=e1659b963e7740de18a3a7297641c31c73b243c0;p=llvm [CVP] After proving that @llvm.with.overflow()/@llvm.sat() don't overflow, also try to prove other no-wrap Summary: CVP, unlike InstCombine, does not run till exaustion. It only does a single pass. When dealing with those special binops, if we prove that they can safely be demoted into their usual binop form, we do set the no-wrap we deduced. But when dealing with usual binops, we try to deduce both no-wraps. So if we convert e.g. @llvm.uadd.with.overflow() to `add nuw`, we won't attempt to check whether it can be `add nuw nsw`. This patch proposes to call `processBinOp()` on newly-created binop, which is identical to what we do for div/rem already. Reviewers: nikic, spatel, reames Reviewed By: nikic Subscribers: hiraditya, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D69183 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@375273 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp b/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp index 52a779520a5..4ed0f2e16c8 100644 --- a/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp +++ b/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp @@ -473,8 +473,10 @@ static void setDeducedOverflowingFlags(Value *V, Instruction::BinaryOps Opcode, } } +static bool processBinOp(BinaryOperator *BinOp, LazyValueInfo *LVI); + // Rewrite this with.overflow intrinsic as non-overflowing. -static void processOverflowIntrinsic(WithOverflowInst *WO) { +static void processOverflowIntrinsic(WithOverflowInst *WO, LazyValueInfo *LVI) { IRBuilder<> B(WO); Instruction::BinaryOps Opcode = WO->getBinaryOp(); bool NSW = WO->isSigned(); @@ -492,9 +494,13 @@ static void processOverflowIntrinsic(WithOverflowInst *WO) { WO->replaceAllUsesWith(NewI); WO->eraseFromParent(); ++NumOverflows; + + // See if we can infer the other no-wrap too. + if (auto *BO = dyn_cast(NewOp)) + processBinOp(BO, LVI); } -static void processSaturatingInst(SaturatingInst *SI) { +static void processSaturatingInst(SaturatingInst *SI, LazyValueInfo *LVI) { Instruction::BinaryOps Opcode = SI->getBinaryOp(); bool NSW = SI->isSigned(); bool NUW = !SI->isSigned(); @@ -506,6 +512,10 @@ static void processSaturatingInst(SaturatingInst *SI) { SI->replaceAllUsesWith(BinOp); SI->eraseFromParent(); ++NumSaturating; + + // See if we can infer the other no-wrap too. + if (auto *BO = dyn_cast(BinOp)) + processBinOp(BO, LVI); } /// Infer nonnull attributes for the arguments at the specified callsite. @@ -515,14 +525,14 @@ static bool processCallSite(CallSite CS, LazyValueInfo *LVI) { if (auto *WO = dyn_cast(CS.getInstruction())) { if (WO->getLHS()->getType()->isIntegerTy() && willNotOverflow(WO, LVI)) { - processOverflowIntrinsic(WO); + processOverflowIntrinsic(WO, LVI); return true; } } if (auto *SI = dyn_cast(CS.getInstruction())) { if (SI->getType()->isIntegerTy() && willNotOverflow(SI, LVI)) { - processSaturatingInst(SI); + processSaturatingInst(SI, LVI); return true; } } diff --git a/test/Transforms/CorrelatedValuePropagation/overflows.ll b/test/Transforms/CorrelatedValuePropagation/overflows.ll index 05c1003db51..211e63aafde 100644 --- a/test/Transforms/CorrelatedValuePropagation/overflows.ll +++ b/test/Transforms/CorrelatedValuePropagation/overflows.ll @@ -38,7 +38,7 @@ define i32 @signed_add(i32 %x, i32 %y) { ; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[Y:%.*]], 0 ; CHECK-NEXT: br i1 [[CMP]], label [[LAND_LHS_TRUE:%.*]], label [[LOR_LHS_FALSE:%.*]] ; CHECK: land.lhs.true: -; CHECK-NEXT: [[TMP0:%.*]] = sub nsw i32 2147483647, [[Y]] +; CHECK-NEXT: [[TMP0:%.*]] = sub nuw nsw i32 2147483647, [[Y]] ; CHECK-NEXT: [[TMP1:%.*]] = insertvalue { i32, i1 } { i32 undef, i1 false }, i32 [[TMP0]], 0 ; CHECK-NEXT: [[TMP2:%.*]] = extractvalue { i32, i1 } [[TMP1]], 1 ; CHECK-NEXT: br i1 [[TMP2]], label [[TRAP:%.*]], label [[CONT:%.*]] @@ -116,7 +116,7 @@ cond.end: ; preds = %cond.false, %cont, define i32 @unsigned_add(i32 %x, i32 %y) { ; CHECK-LABEL: @unsigned_add( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[TMP0:%.*]] = sub nuw i32 -1, [[Y:%.*]] +; CHECK-NEXT: [[TMP0:%.*]] = sub nuw nsw i32 -1, [[Y:%.*]] ; CHECK-NEXT: [[TMP1:%.*]] = insertvalue { i32, i1 } { i32 undef, i1 false }, i32 [[TMP0]], 0 ; CHECK-NEXT: [[TMP2:%.*]] = extractvalue { i32, i1 } [[TMP1]], 1 ; CHECK-NEXT: br i1 [[TMP2]], label [[TRAP:%.*]], label [[CONT:%.*]] @@ -182,7 +182,7 @@ define i32 @signed_sub(i32 %x, i32 %y) { ; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i32 [[Y]], 0 ; CHECK-NEXT: br i1 [[CMP2]], label [[COND_FALSE]], label [[LAND_LHS_TRUE3:%.*]] ; CHECK: land.lhs.true3: -; CHECK-NEXT: [[TMP4:%.*]] = add nsw i32 [[Y]], -2147483648 +; CHECK-NEXT: [[TMP4:%.*]] = add nuw nsw i32 [[Y]], -2147483648 ; CHECK-NEXT: [[TMP5:%.*]] = insertvalue { i32, i1 } { i32 undef, i1 false }, i32 [[TMP4]], 0 ; CHECK-NEXT: [[TMP6:%.*]] = extractvalue { i32, i1 } [[TMP5]], 1 ; CHECK-NEXT: br i1 [[TMP6]], label [[TRAP]], label [[CONT4:%.*]] @@ -506,7 +506,7 @@ define i32 @unsigned_mul(i32 %x) { ; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i32 [[X:%.*]], 10000 ; CHECK-NEXT: br i1 [[CMP]], label [[COND_END:%.*]], label [[COND_FALSE:%.*]] ; CHECK: cond.false: -; CHECK-NEXT: [[MULO1:%.*]] = mul nuw i32 [[X]], 100 +; CHECK-NEXT: [[MULO1:%.*]] = mul nuw nsw i32 [[X]], 100 ; CHECK-NEXT: [[TMP0:%.*]] = insertvalue { i32, i1 } { i32 undef, i1 false }, i32 [[MULO1]], 0 ; CHECK-NEXT: [[RES:%.*]] = extractvalue { i32, i1 } [[TMP0]], 0 ; CHECK-NEXT: [[OV:%.*]] = extractvalue { i32, i1 } [[TMP0]], 1 @@ -760,7 +760,7 @@ define i8 @uadd_sat_no_overflow(i8 %x) { ; CHECK-NEXT: call void @llvm.trap() ; CHECK-NEXT: unreachable ; CHECK: cont: -; CHECK-NEXT: [[RES1:%.*]] = add nuw i8 [[X]], 100 +; CHECK-NEXT: [[RES1:%.*]] = add nuw nsw i8 [[X]], 100 ; CHECK-NEXT: ret i8 [[RES1]] ; %cmp = icmp ugt i8 %x, 27 @@ -806,7 +806,7 @@ define i8 @sadd_sat_no_overflow(i8 %x) { ; CHECK-NEXT: call void @llvm.trap() ; CHECK-NEXT: unreachable ; CHECK: cont: -; CHECK-NEXT: [[RES1:%.*]] = add nsw i8 [[X]], 20 +; CHECK-NEXT: [[RES1:%.*]] = add nuw nsw i8 [[X]], 20 ; CHECK-NEXT: ret i8 [[RES1]] ; %cmp = icmp ugt i8 %x, 107 @@ -852,7 +852,7 @@ define i8 @usub_sat_no_overflow(i8 %x) { ; CHECK-NEXT: call void @llvm.trap() ; CHECK-NEXT: unreachable ; CHECK: cont: -; CHECK-NEXT: [[RES1:%.*]] = sub nuw i8 [[X]], 100 +; CHECK-NEXT: [[RES1:%.*]] = sub nuw nsw i8 [[X]], 100 ; CHECK-NEXT: ret i8 [[RES1]] ; %cmp = icmp ult i8 %x, 228 @@ -898,7 +898,7 @@ define i8 @ssub_sat_no_overflow(i8 %x) { ; CHECK-NEXT: call void @llvm.trap() ; CHECK-NEXT: unreachable ; CHECK: cont: -; CHECK-NEXT: [[RES1:%.*]] = sub nsw i8 [[X]], 20 +; CHECK-NEXT: [[RES1:%.*]] = sub nuw nsw i8 [[X]], 20 ; CHECK-NEXT: ret i8 [[RES1]] ; %cmp = icmp ult i8 %x, 148 @@ -982,7 +982,7 @@ define i1 @uadd_and_cmp(i32 %x, i32 %y) #0 { ; CHECK-NEXT: [[CMP2:%.*]] = icmp ult i32 [[Y:%.*]], 10 ; CHECK-NEXT: br i1 [[CMP2]], label [[CONT2:%.*]], label [[OUT]] ; CHECK: cont2: -; CHECK-NEXT: [[RES1:%.*]] = add nuw i32 [[X]], [[Y]] +; CHECK-NEXT: [[RES1:%.*]] = add nuw nsw i32 [[X]], [[Y]] ; CHECK-NEXT: [[TMP0:%.*]] = insertvalue { i32, i1 } { i32 undef, i1 false }, i32 [[RES1]], 0 ; CHECK-NEXT: [[ADD:%.*]] = extractvalue { i32, i1 } [[TMP0]], 0 ; CHECK-NEXT: br label [[CONT3:%.*]] @@ -1023,7 +1023,7 @@ define i1 @ssub_and_cmp(i32 %x, i32 %y) #0 { ; CHECK-NEXT: br i1 [[CMP2]], label [[CONT2:%.*]], label [[OUT]] ; CHECK: cont2: ; CHECK-NEXT: [[OFFSET:%.*]] = add nuw nsw i32 [[X]], 9 -; CHECK-NEXT: [[RES1:%.*]] = sub nsw i32 [[OFFSET]], [[Y]] +; CHECK-NEXT: [[RES1:%.*]] = sub nuw nsw i32 [[OFFSET]], [[Y]] ; CHECK-NEXT: [[TMP0:%.*]] = insertvalue { i32, i1 } { i32 undef, i1 false }, i32 [[RES1]], 0 ; CHECK-NEXT: [[SUB:%.*]] = extractvalue { i32, i1 } [[TMP0]], 0 ; CHECK-NEXT: br label [[CONT3:%.*]] @@ -1066,7 +1066,7 @@ define i1 @usub_and_cmp(i32 %x, i32 %y) #0 { ; CHECK-NEXT: br i1 [[CMP2]], label [[CONT2:%.*]], label [[OUT]] ; CHECK: cont2: ; CHECK-NEXT: [[OFFSET:%.*]] = add nuw nsw i32 [[X]], 9 -; CHECK-NEXT: [[RES1:%.*]] = sub nuw i32 [[OFFSET]], [[Y]] +; CHECK-NEXT: [[RES1:%.*]] = sub nuw nsw i32 [[OFFSET]], [[Y]] ; CHECK-NEXT: [[TMP0:%.*]] = insertvalue { i32, i1 } { i32 undef, i1 false }, i32 [[RES1]], 0 ; CHECK-NEXT: [[SUB:%.*]] = extractvalue { i32, i1 } [[TMP0]], 0 ; CHECK-NEXT: br label [[CONT3:%.*]] @@ -1155,7 +1155,7 @@ define i1 @umul_and_cmp(i32 %x, i32 %y) #0 { ; CHECK-NEXT: [[CMP2:%.*]] = icmp ult i32 [[Y:%.*]], 100 ; CHECK-NEXT: br i1 [[CMP2]], label [[CONT2:%.*]], label [[OUT]] ; CHECK: cont2: -; CHECK-NEXT: [[RES1:%.*]] = mul nuw i32 [[X]], [[Y]] +; CHECK-NEXT: [[RES1:%.*]] = mul nuw nsw i32 [[X]], [[Y]] ; CHECK-NEXT: [[TMP0:%.*]] = insertvalue { i32, i1 } { i32 undef, i1 false }, i32 [[RES1]], 0 ; CHECK-NEXT: [[MUL:%.*]] = extractvalue { i32, i1 } [[TMP0]], 0 ; CHECK-NEXT: br label [[CONT3:%.*]]