Value *Val, BasicBlock *BB);
bool solveBlockValuePHINode(LVILatticeVal &BBLV,
PHINode *PN, BasicBlock *BB);
+ bool solveBlockValueSelect(LVILatticeVal &BBLV,
+ SelectInst *S, BasicBlock *BB);
bool solveBlockValueConstantRange(LVILatticeVal &BBLV,
Instruction *BBI, BasicBlock *BB);
void mergeAssumeBlockValueConstantRange(Value *Val, LVILatticeVal &BBLV,
return true;
}
+ if (auto *SI = dyn_cast<SelectInst>(BBI)) {
+ if (!solveBlockValueSelect(Res, SI, BB))
+ return false;
+ insertResult(Val, BB, Res);
+ return true;
+ }
+
// If this value is a nonnull pointer, record it's range and bailout.
PointerType *PT = dyn_cast<PointerType>(BBI->getType());
if (PT && isKnownNonNull(BBI)) {
}
}
+bool LazyValueInfoCache::solveBlockValueSelect(LVILatticeVal &BBLV,
+ SelectInst *SI, BasicBlock *BB) {
+
+ // Recurse on our inputs if needed
+ if (!hasBlockValue(SI->getTrueValue(), BB)) {
+ if (pushBlockValue(std::make_pair(BB, SI->getTrueValue())))
+ return false;
+ BBLV.markOverdefined();
+ return true;
+ }
+ LVILatticeVal TrueVal = getBlockValue(SI->getTrueValue(), BB);
+ // If we hit overdefined, don't ask more queries. We want to avoid poisoning
+ // extra slots in the table if we can.
+ if (TrueVal.isOverdefined()) {
+ BBLV.markOverdefined();
+ return true;
+ }
+
+ if (!hasBlockValue(SI->getFalseValue(), BB)) {
+ if (pushBlockValue(std::make_pair(BB, SI->getFalseValue())))
+ return false;
+ BBLV.markOverdefined();
+ return true;
+ }
+ LVILatticeVal FalseVal = getBlockValue(SI->getFalseValue(), BB);
+ // If we hit overdefined, don't ask more queries. We want to avoid poisoning
+ // extra slots in the table if we can.
+ if (FalseVal.isOverdefined()) {
+ BBLV.markOverdefined();
+ return true;
+ }
+
+ LVILatticeVal Result; // Start Undefined.
+ Result.mergeIn(TrueVal, DL);
+ Result.mergeIn(FalseVal, DL);
+ assert(!Result.isOverdefined() && "Should have exited previously");
+ BBLV = Result;
+ return true;
+}
+
bool LazyValueInfoCache::solveBlockValueConstantRange(LVILatticeVal &BBLV,
Instruction *BBI,
BasicBlock *BB) {
ret i32 %sel
; CHECK: ret i32 1
}
+
+define i1 @test1(i32* %p, i1 %unknown) {
+; CHECK-LABEL: @test1
+ %pval = load i32, i32* %p
+ %cmp1 = icmp slt i32 %pval, 255
+ br i1 %cmp1, label %next, label %exit
+
+next:
+ %min = select i1 %unknown, i32 %pval, i32 5
+ ;; TODO: This pointless branch shouldn't be neccessary
+ br label %next2
+next2:
+; CHECK-LABEL: next2:
+; CHECK: ret i1 false
+ %res = icmp eq i32 %min, 255
+ ret i1 %res
+
+exit:
+; CHECK-LABEL: exit:
+; CHECK: ret i1 true
+ ret i1 true
+}
+
+; Check that we take a conservative meet
+define i1 @test2(i32* %p, i32 %qval, i1 %unknown) {
+; CHECK-LABEL: test2
+ %pval = load i32, i32* %p
+ %cmp1 = icmp slt i32 %pval, 255
+ br i1 %cmp1, label %next, label %exit
+
+next:
+ %min = select i1 %unknown, i32 %pval, i32 %qval
+ ;; TODO: This pointless branch shouldn't be neccessary
+ br label %next2
+next2:
+; CHECK-LABEL: next2
+; CHECK: ret i1 %res
+ %res = icmp eq i32 %min, 255
+ ret i1 %res
+
+exit:
+; CHECK-LABEL: exit:
+; CHECK: ret i1 true
+ ret i1 true
+}
+
+; Same as @test2, but for the opposite select input
+define i1 @test3(i32* %p, i32 %qval, i1 %unknown) {
+; CHECK-LABEL: test3
+ %pval = load i32, i32* %p
+ %cmp1 = icmp slt i32 %pval, 255
+ br i1 %cmp1, label %next, label %exit
+
+next:
+ %min = select i1 %unknown, i32 %qval, i32 %pval
+ ;; TODO: This pointless branch shouldn't be neccessary
+ br label %next2
+next2:
+; CHECK-LABEL: next2
+; CHECK: ret i1 %res
+ %res = icmp eq i32 %min, 255
+ ret i1 %res
+
+exit:
+; CHECK-LABEL: exit:
+; CHECK: ret i1 true
+ ret i1 true
+}
+