From 66c6de61eea9d88061648fe505f420b7cb958df5 Mon Sep 17 00:00:00 2001 From: Philip Reames Date: Tue, 11 Nov 2014 23:33:19 +0000 Subject: [PATCH] Canonicalize an assume(load != null) into !nonnull metadata We currently have two ways of informing the optimizer that the result of a load is never null: metadata and assume. This change converts the second in to the former. This avoids a need to implement optimizations using both forms. We should probably extend this basic idea to metadata of other forms; in particular, range metadata. We view is that assumes should be considered a "last resort" for when there isn't a more canonical way to represent something. Reviewed by: Hal Differential Revision: http://reviews.llvm.org/D5951 llvm-svn: 221737 --- .../Transforms/InstCombine/InstCombineCalls.cpp | 20 ++++++ llvm/test/Transforms/InstCombine/assume.ll | 74 ++++++++++++++++++++++ 2 files changed, 94 insertions(+) diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp index 5a70d8b..8987ee0 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp @@ -1102,6 +1102,26 @@ Instruction *InstCombiner::visitCallInst(CallInst &CI) { 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); diff --git a/llvm/test/Transforms/InstCombine/assume.ll b/llvm/test/Transforms/InstCombine/assume.ll index b328fb6..7e45c04 100644 --- a/llvm/test/Transforms/InstCombine/assume.ll +++ b/llvm/test/Transforms/InstCombine/assume.ll @@ -186,6 +186,80 @@ entry: ; 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 } -- 2.7.4