Index: llvm/trunk/lib/Transforms/InstCombine/InstCombineCalls.cpp =================================================================== --- llvm/trunk/lib/Transforms/InstCombine/InstCombineCalls.cpp +++ llvm/trunk/lib/Transforms/InstCombine/InstCombineCalls.cpp @@ -1102,6 +1102,26 @@ return EraseInstFromFunction(*II); } + // assume( (load addr) != null ) -> add 'nonnull' metadata to load + // (if assume is valid at the load) + if (ICmpInst* ICmp = dyn_cast(IIOperand)) { + Value *LHS = ICmp->getOperand(0); + Value *RHS = ICmp->getOperand(1); + if (ICmpInst::ICMP_NE == ICmp->getPredicate() && + isa(LHS) && + isa(RHS) && + RHS->getType()->isPointerTy() && + cast(RHS)->isNullValue()) { + LoadInst* LI = cast(LHS); + if (isValidAssumeForContext(II, LI, DL, DT)) { + MDNode* MD = MDNode::get(II->getContext(), ArrayRef()); + 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); Index: llvm/trunk/test/Transforms/InstCombine/assume.ll =================================================================== --- llvm/trunk/test/Transforms/InstCombine/assume.ll +++ llvm/trunk/test/Transforms/InstCombine/assume.ll @@ -186,6 +186,80 @@ ; 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 }