llvm.org GIT mirror llvm / fe0d65b
[InstSimplify] Handle some overflow intrinsics in InstSimplify This change does a few things: - Move some InstCombine transforms to InstSimplify - Run SimplifyCall from within InstCombine::visitCallInst - Teach InstSimplify to fold [us]mul_with_overflow(X, undef) to 0. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@237995 91177308-0d34-0410-b5e6-96231b3b80d8 David Majnemer 4 years ago
5 changed file(s) with 75 addition(s) and 19 deletion(s). Raw diff Collapse all Expand all
35553555 }
35563556
35573557 template
3558 static Value *SimplifyIntrinsic(Intrinsic::ID IID, IterTy ArgBegin, IterTy ArgEnd,
3558 static Value *SimplifyIntrinsic(Function *F, IterTy ArgBegin, IterTy ArgEnd,
35593559 const Query &Q, unsigned MaxRecurse) {
3560 Intrinsic::ID IID = F->getIntrinsicID();
3561 unsigned NumOperands = std::distance(ArgBegin, ArgEnd);
3562 Type *ReturnType = F->getReturnType();
3563
3564 // Binary Ops
3565 if (NumOperands == 2) {
3566 Value *LHS = *ArgBegin;
3567 Value *RHS = *(ArgBegin + 1);
3568 if (IID == Intrinsic::usub_with_overflow ||
3569 IID == Intrinsic::ssub_with_overflow) {
3570 // X - X -> { 0, false }
3571 if (LHS == RHS)
3572 return Constant::getNullValue(ReturnType);
3573
3574 // X - undef -> undef
3575 // undef - X -> undef
3576 if (isa(LHS) || isa(RHS))
3577 return UndefValue::get(ReturnType);
3578 }
3579
3580 if (IID == Intrinsic::uadd_with_overflow ||
3581 IID == Intrinsic::sadd_with_overflow) {
3582 // X + undef -> undef
3583 if (isa(RHS))
3584 return UndefValue::get(ReturnType);
3585 }
3586
3587 if (IID == Intrinsic::umul_with_overflow ||
3588 IID == Intrinsic::smul_with_overflow) {
3589 // X * 0 -> { 0, false }
3590 if (match(RHS, m_Zero()))
3591 return Constant::getNullValue(ReturnType);
3592
3593 // X * undef -> { 0, false }
3594 if (match(RHS, m_Undef()))
3595 return Constant::getNullValue(ReturnType);
3596 }
3597 }
3598
35603599 // Perform idempotent optimizations
35613600 if (!IsIdempotent(IID))
35623601 return nullptr;
35633602
35643603 // Unary Ops
3565 if (std::distance(ArgBegin, ArgEnd) == 1)
3604 if (NumOperands == 1)
35663605 if (IntrinsicInst *II = dyn_cast(*ArgBegin))
35673606 if (II->getIntrinsicID() == IID)
35683607 return II;
35863625 if (!F)
35873626 return nullptr;
35883627
3589 if (Intrinsic::ID IID = F->getIntrinsicID())
3590 if (Value *Ret =
3591 SimplifyIntrinsic(IID, ArgBegin, ArgEnd, Q, MaxRecurse))
3628 if (F->isIntrinsic())
3629 if (Value *Ret = SimplifyIntrinsic(F, ArgBegin, ArgEnd, Q, MaxRecurse))
35923630 return Ret;
35933631
35943632 if (!canConstantFoldCallTo(F))
1212
1313 #include "InstCombineInternal.h"
1414 #include "llvm/ADT/Statistic.h"
15 #include "llvm/Analysis/InstructionSimplify.h"
1516 #include "llvm/Analysis/MemoryBuiltins.h"
1617 #include "llvm/IR/CallSite.h"
1718 #include "llvm/IR/Dominators.h"
322323 /// the heavy lifting.
323324 ///
324325 Instruction *InstCombiner::visitCallInst(CallInst &CI) {
326 auto Args = CI.arg_operands();
327 if (Value *V = SimplifyCall(CI.getCalledValue(), Args.begin(), Args.end(), DL,
328 TLI, DT, AC))
329 return ReplaceInstUsesWith(CI, V);
330
325331 if (isFreeCall(&CI, TLI))
326332 return visitFree(CI);
327333
21382138 }
21392139 // FALL THROUGH uadd into sadd
21402140 case OCF_SIGNED_ADD: {
2141 // X + undef -> undef
2142 if (isa(RHS))
2143 return SetResult(RHS, UndefValue::get(Builder->getInt1Ty()), false);
2144
21452141 // X + 0 -> {X, false}
21462142 if (match(RHS, m_Zero()))
21472143 return SetResult(LHS, Builder->getFalse(), false);
21562152
21572153 case OCF_UNSIGNED_SUB:
21582154 case OCF_SIGNED_SUB: {
2159 // undef - X -> undef
2160 if (isa(LHS))
2161 return SetResult(LHS, UndefValue::get(Builder->getInt1Ty()), false);
2162
2163 // X - undef -> undef
2164 if (isa(RHS))
2165 return SetResult(RHS, UndefValue::get(Builder->getInt1Ty()), false);
2166
21672155 // X - 0 -> {X, false}
21682156 if (match(RHS, m_Zero()))
21692157 return SetResult(LHS, Builder->getFalse(), false);
417417 ; CHECK-NEXT: ret %ov.result.32 %1
418418 }
419419
420 define %ov.result.32 @never_overflows_ssub(i32 %a) {
420 define %ov.result.32 @never_overflows_ssub_test0(i32 %a) {
421421 %x = call %ov.result.32 @llvm.ssub.with.overflow.i32(i32 %a, i32 0)
422422 ret %ov.result.32 %x
423 ; CHECK-LABEL: @never_overflows_ssub
423 ; CHECK-LABEL: @never_overflows_ssub_test0
424424 ; CHECK-NEXT: %[[x:.*]] = insertvalue %ov.result.32 { i32 undef, i1 false }, i32 %a, 0
425425 ; CHECK-NEXT: ret %ov.result.32 %[[x]]
426426 }
0 ; RUN: opt < %s -instsimplify -S | FileCheck %s
11
22 declare {i8, i1} @llvm.uadd.with.overflow.i8(i8 %a, i8 %b)
3 declare {i8, i1} @llvm.usub.with.overflow.i8(i8 %a, i8 %b)
4 declare {i8, i1} @llvm.ssub.with.overflow.i8(i8 %a, i8 %b)
5 declare {i8, i1} @llvm.umul.with.overflow.i8(i8 %a, i8 %b)
36
47 define i1 @test_uadd1() {
58 ; CHECK-LABEL: @test_uadd1(
1518 %result = extractvalue {i8, i1} %x, 0
1619 ret i8 %result
1720 ; CHECK-NEXT: ret i8 42
21 }
22
23 define {i8, i1} @test_usub1(i8 %V) {
24 ; CHECK-LABEL: @test_usub1(
25 %x = call {i8, i1} @llvm.usub.with.overflow.i8(i8 %V, i8 %V)
26 ret {i8, i1} %x
27 ; CHECK-NEXT: ret { i8, i1 } zeroinitializer
28 }
29
30 define {i8, i1} @test_ssub1(i8 %V) {
31 ; CHECK-LABEL: @test_ssub1(
32 %x = call {i8, i1} @llvm.ssub.with.overflow.i8(i8 %V, i8 %V)
33 ret {i8, i1} %x
34 ; CHECK-NEXT: ret { i8, i1 } zeroinitializer
35 }
36
37 define {i8, i1} @test_umul1(i8 %V) {
38 ; CHECK-LABEL: @test_umul1(
39 %x = call {i8, i1} @llvm.umul.with.overflow.i8(i8 %V, i8 0)
40 ret {i8, i1} %x
41 ; CHECK-NEXT: ret { i8, i1 } zeroinitializer
1842 }
1943
2044 declare i256 @llvm.cttz.i256(i256 %src, i1 %is_zero_undef)