return EraseInstFromFunction(*II);
}
+ // assume( (load addr) != null ) -> add 'nonnull' metadata to load
+ // (if assume is valid at the load)
+ if (ICmpInst* ICmp = dyn_cast<ICmpInst>(IIOperand)) {
+ Value *LHS = ICmp->getOperand(0);
+ Value *RHS = ICmp->getOperand(1);
+ if (ICmpInst::ICMP_NE == ICmp->getPredicate() &&
+ isa<LoadInst>(LHS) &&
+ isa<Constant>(RHS) &&
+ RHS->getType()->isPointerTy() &&
+ cast<Constant>(RHS)->isNullValue()) {
+ LoadInst* LI = cast<LoadInst>(LHS);
+ if (isValidAssumeForContext(II, LI, DL, DT)) {
+ MDNode* MD = MDNode::get(II->getContext(), ArrayRef<Value*>());
+ LI->setMetadata(LLVMContext::MD_nonnull, MD);
+ return EraseInstFromFunction(*II);
+ }
+ }
+ // TODO: apply nonnull return attributes to calls and invokes
+ // TODO: apply range metadata for range check patterns?
+ }
// If there is a dominating assume with the same condition as this one,
// then this one is redundant, and should be removed.
APInt KnownZero(1, 0), KnownOne(1, 0);
; CHECK: ret i32 0
}
+declare void @escape(i32* %a)
+
+; Do we canonicalize a nonnull assumption on a load into
+; metadata form?
+define i1 @nonnull1(i32** %a) {
+entry:
+ %load = load i32** %a
+ %cmp = icmp ne i32* %load, null
+ tail call void @llvm.assume(i1 %cmp)
+ tail call void @escape(i32* %load)
+ %rval = icmp eq i32* %load, null
+ ret i1 %rval
+
+; CHECK-LABEL: @nonnull1
+; CHECK: !nonnull
+; CHECK-NOT: call void @llvm.assume
+; CHECK: ret i1 false
+}
+
+; Make sure the above canonicalization applies only
+; to pointer types. Doing otherwise would be illegal.
+define i1 @nonnull2(i32* %a) {
+entry:
+ %load = load i32* %a
+ %cmp = icmp ne i32 %load, 0
+ tail call void @llvm.assume(i1 %cmp)
+ %rval = icmp eq i32 %load, 0
+ ret i1 %rval
+
+; CHECK-LABEL: @nonnull2
+; CHECK-NOT: !nonnull
+; CHECK: call void @llvm.assume
+}
+
+; Make sure the above canonicalization does not trigger
+; if the assume is control dependent on something else
+define i1 @nonnull3(i32** %a, i1 %control) {
+entry:
+ %load = load i32** %a
+ %cmp = icmp ne i32* %load, null
+ br i1 %control, label %taken, label %not_taken
+taken:
+ tail call void @llvm.assume(i1 %cmp)
+ %rval = icmp eq i32* %load, null
+ ret i1 %rval
+not_taken:
+ ret i1 true
+
+; CHECK-LABEL: @nonnull3
+; CHECK-NOT: !nonnull
+; CHECK: call void @llvm.assume
+}
+
+; Make sure the above canonicalization does not trigger
+; if the path from the load to the assume is potentially
+; interrupted by an exception being thrown
+define i1 @nonnull4(i32** %a) {
+entry:
+ %load = load i32** %a
+ ;; This call may throw!
+ tail call void @escape(i32* %load)
+ %cmp = icmp ne i32* %load, null
+ tail call void @llvm.assume(i1 %cmp)
+ %rval = icmp eq i32* %load, null
+ ret i1 %rval
+
+; CHECK-LABEL: @nonnull4
+; CHECK-NOT: !nonnull
+; CHECK: call void @llvm.assume
+}
+
+
+
+
attributes #0 = { nounwind uwtable }
attributes #1 = { nounwind }