llvm.org GIT mirror llvm / b4afe9c
[SCEV] Make SCEV or modeling more aggressive. Use haveNoCommonBitsSet to figure out whether an "or" instruction is equivalent to addition. This handles more cases than just checking for a constant on the RHS. Differential Revision: https://reviews.llvm.org/D32239 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@300746 91177308-0d34-0410-b5e6-96231b3b80d8 Eli Friedman 2 years ago
2 changed file(s) with 44 addition(s) and 22 deletion(s). Raw diff Collapse all Expand all
53275327 break;
53285328
53295329 case Instruction::Or:
5330 // If the RHS of the Or is a constant, we may have something like:
5331 // X*4+1 which got turned into X*4|1. Handle this as an Add so loop
5332 // optimizations will transparently handle this case.
5333 //
5334 // In order for this transformation to be safe, the LHS must be of the
5335 // form X*(2^n) and the Or constant must be less than 2^n.
5336 if (ConstantInt *CI = dyn_cast(BO->RHS)) {
5337 const SCEV *LHS = getSCEV(BO->LHS);
5338 const APInt &CIVal = CI->getValue();
5339 if (GetMinTrailingZeros(LHS) >=
5340 (CIVal.getBitWidth() - CIVal.countLeadingZeros())) {
5341 // Build a plain add SCEV.
5342 const SCEV *S = getAddExpr(LHS, getSCEV(CI));
5343 // If the LHS of the add was an addrec and it has no-wrap flags,
5344 // transfer the no-wrap flags, since an or won't introduce a wrap.
5345 if (const SCEVAddRecExpr *NewAR = dyn_cast(S)) {
5346 const SCEVAddRecExpr *OldAR = cast(LHS);
5347 const_cast(NewAR)->setNoWrapFlags(
5348 OldAR->getNoWrapFlags());
5349 }
5350 return S;
5351 }
5330 // Use ValueTracking to check whether this is actually an add.
5331 if (haveNoCommonBitsSet(BO->LHS, BO->RHS, getDataLayout(), &AC,
5332 nullptr, &DT)) {
5333 // There aren't any common bits set, so the add can't wrap.
5334 auto Flags = SCEV::NoWrapFlags(SCEV::FlagNUW | SCEV::FlagNSW);
5335 return getAddExpr(getSCEV(BO->LHS), getSCEV(BO->RHS), Flags);
53525336 }
53535337 break;
53545338
0 ; RUN: opt < %s -analyze -scalar-evolution | FileCheck %s
1
2 declare void @z(i32)
3 declare void @z2(i64)
4
5 define void @fun(i1 %bool, i32 %x) {
6 entry:
7 br label %body
8 body:
9 %i = phi i32 [ 0, %entry ], [ %i.next, %body ]
10 %bottom_zero = mul i32 %i, 2
11 %a = or i32 %bottom_zero, 1
12 call void @z(i32 %a)
13 %bool_ext = zext i1 %bool to i32
14 %b = or i32 %bool_ext, %bottom_zero
15 call void @z(i32 %b)
16 %shifted = lshr i32 %x, 31
17 %c = or i32 %shifted, %bottom_zero
18 call void @z(i32 %c)
19 %i_ext = zext i32 %i to i64
20 %d = or i64 %i_ext, 4294967296
21 call void @z2(i64 %d)
22 %i.next = add i32 %i, 1
23 %cond = icmp eq i32 %i.next, 10
24 br i1 %cond, label %exit, label %body
25 exit:
26 ret void
27 }
28
29 ; CHECK: %a = or i32 %bottom_zero, 1
30 ; CHECK-NEXT: --> {1,+,2}<%body>
31 ; CHECK: %b = or i32 %bool_ext, %bottom_zero
32 ; CHECK-NEXT: --> {(zext i1 %bool to i32),+,2}
33 ; CHECK: %c = or i32 %shifted, %bottom_zero
34 ; CHECK-NEXT: --> {(%x /u -2147483648),+,2}<%body>
35 ; CHECK: %d = or i64 %i_ext, 4294967296
36 ; CHECK-NEXT: --> {4294967296,+,1}<%body>
37