llvm.org GIT mirror
[LVI] Take guards into account Teach LVI to gather control dependant constraints from guards. Reviewed By: sanjoy Differential Revision: https://reviews.llvm.org/D23358 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@278518 91177308-0d34-0410-b5e6-96231b3b80d8 Artur Pilipenko 3 years ago
2 changed file(s) with 124 addition(s) and 11 deletion(s).
 25 25 #include "llvm/IR/Dominators.h" 26 26 #include "llvm/IR/Instructions.h" 27 27 #include "llvm/IR/IntrinsicInst.h" 28 #include "llvm/IR/Intrinsics.h" 28 29 #include "llvm/IR/LLVMContext.h" 29 30 #include "llvm/IR/PatternMatch.h" 30 31 #include "llvm/IR/ValueHandle.h" 470 471 BasicBlock *BB); 471 472 bool solveBlockValueCast(LVILatticeVal &BBLV, Instruction *BBI, 472 473 BasicBlock *BB); 473 void intersectAssumeBlockValueConstantRange(Value *Val, LVILatticeVal &BBLV, 474 Instruction *BBI);⏎ 474 void intersectAssumeOrGuardBlockValueConstantRange(Value *Val,⏎ 475 LVILatticeVal &BBLV, 476 Instruction *BBI); 475 477 476 478 void solve(); 477 479 863 865 864 866 // If we can determine a constraint on the value given conditions assumed by 865 867 // the program, intersect those constraints with BBLV 866 void LazyValueInfoCache::intersectAssumeBlockValueConstantRange(Value *Val, 867 LVILatticeVal &BBLV, 868 Instruction *BBI) {⏎ 868 void LazyValueInfoCache::intersectAssumeOrGuardBlockValueConstantRange(⏎ 869 Value *Val, LVILatticeVal &BBLV, Instruction *BBI) { 869 870 BBI = BBI ? BBI : dyn_cast(Val); 870 871 if (!BBI) 871 872 return; 878 879 continue; 879 880 880 881 BBLV = intersect(BBLV, getValueFromCondition(Val, I->getArgOperand(0))); 882 } 883 884 // If guards are not used in the module, don't spend time looking for them 885 auto *GuardDecl = BBI->getModule()->getFunction( 886 Intrinsic::getName(Intrinsic::experimental_guard)); 887 if (!GuardDecl || GuardDecl->use_empty()) 888 return; 889 890 for (BasicBlock::iterator I = BBI->getIterator(), 891 E = BBI->getParent()->begin(); I != E; I--) { 892 Value *Cond = nullptr; 893 if (!match(&*I, m_Intrinsic(m_Value(Cond)))) 894 continue; 895 BBLV = intersect(BBLV, getValueFromCondition(Val, Cond)); 881 896 } 882 897 } 883 898 1042 1057 ConstantRange LHSRange = ConstantRange(OperandBitWidth); 1043 1058 if (hasBlockValue(BBI->getOperand(0), BB)) { 1044 1059 LVILatticeVal LHSVal = getBlockValue(BBI->getOperand(0), BB); 1045 intersectAssumeBlockValueConstantRange(BBI->getOperand(0), LHSVal, BBI);⏎ 1060 intersectAssumeOrGuardBlockValueConstantRange(BBI->getOperand(0), LHSVal,⏎ 1061 BBI); 1046 1062 if (LHSVal.isConstantRange()) 1047 1063 LHSRange = LHSVal.getConstantRange(); 1048 1064 } 1119 1135 ConstantRange LHSRange = ConstantRange(OperandBitWidth); 1120 1136 if (hasBlockValue(BBI->getOperand(0), BB)) { 1121 1137 LVILatticeVal LHSVal = getBlockValue(BBI->getOperand(0), BB); 1122 intersectAssumeBlockValueConstantRange(BBI->getOperand(0), LHSVal, BBI);⏎ 1138 intersectAssumeOrGuardBlockValueConstantRange(BBI->getOperand(0), LHSVal,⏎ 1139 BBI); 1123 1140 if (LHSVal.isConstantRange()) 1124 1141 LHSRange = LHSVal.getConstantRange(); 1125 1142 } 1362 1379 1363 1380 // Try to intersect ranges of the BB and the constraint on the edge. 1364 1381 LVILatticeVal InBlock = getBlockValue(Val, BBFrom); 1365 intersectAssumeBlockValueConstantRange(Val, InBlock, BBFrom->getTerminator());⏎ 1382 intersectAssumeOrGuardBlockValueConstantRange(Val, InBlock,⏎ 1383 BBFrom->getTerminator()); 1366 1384 // We can use the context instruction (generically the ultimate instruction 1367 1385 // the calling pass is trying to simplify) here, even though the result of 1368 1386 // this function is generally cached when called from the solve* functions 1371 1389 // functions, the context instruction is not provided. When called from 1372 1390 // LazyValueInfoCache::getValueOnEdge, the context instruction is provided, 1373 1391 // but then the result is not cached. 1374 intersectAssumeBlockValueConstantRange(Val, InBlock, CxtI);⏎ 1392 intersectAssumeOrGuardBlockValueConstantRange(Val, InBlock, CxtI);⏎ 1375 1393 1376 1394 Result = intersect(LocalResult, InBlock); 1377 1395 return true; 1388 1406 solve(); 1389 1407 } 1390 1408 LVILatticeVal Result = getBlockValue(V, BB); 1391 intersectAssumeBlockValueConstantRange(V, Result, CxtI);⏎ 1409 intersectAssumeOrGuardBlockValueConstantRange(V, Result, CxtI);⏎ 1392 1410 1393 1411 DEBUG(dbgs() << " Result = " << Result << "\n"); 1394 1412 return Result; 1404 1422 LVILatticeVal Result = LVILatticeVal::getOverdefined(); 1405 1423 if (auto *I = dyn_cast(V)) 1406 1424 Result = getFromRangeMetadata(I); 1407 intersectAssumeBlockValueConstantRange(V, Result, CxtI);⏎ 1425 intersectAssumeOrGuardBlockValueConstantRange(V, Result, CxtI);⏎ 1408 1426 1409 1427 DEBUG(dbgs() << " Result = " << Result << "\n"); 1410 1428 return Result;
 0 ; RUN: opt -correlated-propagation -S < %s | FileCheck %s 1 2 declare void @llvm.experimental.guard(i1,...) 3 4 define i1 @test1(i32 %a) { 5 ; CHECK-LABEL: @test1( 6 ; CHECK: %alive = icmp eq i32 %a, 8 7 ; CHECK-NEXT: %result = or i1 false, %alive 8 %cmp = icmp ult i32 %a, 16 9 call void(i1,...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ] 10 %dead = icmp eq i32 %a, 16 11 %alive = icmp eq i32 %a, 8 12 %result = or i1 %dead, %alive 13 ret i1 %result 14 } 15 16 define i1 @test2(i32 %a) { 17 ; CHECK-LABEL: @test2( 18 ; CHECK: continue: 19 ; CHECK-NEXT: %alive = icmp eq i32 %a, 8 20 ; CHECK-NEXT: %result = or i1 false, %alive 21 %cmp = icmp ult i32 %a, 16 22 call void(i1,...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ] 23 br label %continue 24 25 continue: 26 %dead = icmp eq i32 %a, 16 27 %alive = icmp eq i32 %a, 8 28 %result = or i1 %dead, %alive 29 ret i1 %result 30 } 31 32 define i1 @test3(i32 %a, i1 %flag) { 33 ; CHECK-LABEL: @test3( 34 ; CHECK: continue: 35 ; CHECK-NEXT: %alive.1 = icmp eq i32 %a, 16 36 ; CHECK-NEXT: %alive.2 = icmp eq i32 %a, 8 37 ; CHECK-NEXT: %result = or i1 %alive.1, %alive.2 38 br i1 %flag, label %true, label %false 39 40 true: 41 %cmp = icmp ult i32 %a, 16 42 call void(i1,...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ] 43 br label %continue 44 45 false: 46 br label %continue 47 48 continue: 49 %alive.1 = icmp eq i32 %a, 16 50 %alive.2 = icmp eq i32 %a, 8 51 %result = or i1 %alive.1, %alive.2 52 ret i1 %result 53 } 54 55 define i1 @test4(i32 %a, i1 %flag) { 56 ; CHECK-LABEL: @test4( 57 ; CHECK: continue: 58 ; CHECK-NEXT: %alive = icmp eq i32 %a, 12 59 ; CHECK-NEXT: %result = or i1 false, %alive 60 br i1 %flag, label %true, label %false 61 62 true: 63 %cmp.t = icmp ult i32 %a, 16 64 call void(i1,...) @llvm.experimental.guard(i1 %cmp.t) [ "deopt"() ] 65 br label %continue 66 67 false: 68 %cmp.f = icmp ult i32 %a, 12 69 call void(i1,...) @llvm.experimental.guard(i1 %cmp.f) [ "deopt"() ] 70 br label %continue 71 72 continue: 73 %dead = icmp eq i32 %a, 16 74 %alive = icmp eq i32 %a, 12 75 %result = or i1 %dead, %alive 76 ret i1 %result 77 } 78 79 define i1 @test5(i32 %a) { 80 ; CHECK-LABEL: @test5( 81 ; CHECK: continue: 82 ; CHECK-NEXT: %alive = icmp eq i32 %a.plus.8, 16 83 ; CHECK-NEXT: %result = or i1 false, %alive 84 %cmp = icmp ult i32 %a, 16 85 call void(i1,...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ] 86 %a.plus.8 = add i32 %a, 8 87 br label %continue 88 89 continue: 90 %dead = icmp eq i32 %a.plus.8, 24 91 %alive = icmp eq i32 %a.plus.8, 16 92 %result = or i1 %dead, %alive 93 ret i1 %result 94 }