Index: llvm/trunk/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp =================================================================== --- llvm/trunk/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp +++ llvm/trunk/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp @@ -44,6 +44,7 @@ bool processMemAccess(Instruction *I); bool processCmp(CmpInst *C); bool processSwitch(SwitchInst *SI); + bool processCallSite(CallSite CS); public: static char ID; @@ -309,6 +310,32 @@ return Changed; } +/// processCallSite - Infer nonnull attributes for the arguments at the +/// specified callsite. +bool CorrelatedValuePropagation::processCallSite(CallSite CS) { + bool Changed = false; + + unsigned ArgNo = 0; + for (Value *V : CS.args()) { + PointerType *Type = dyn_cast(V->getType()); + + if (Type && !CS.paramHasAttr(ArgNo + 1, Attribute::NonNull) && + LVI->getPredicateAt(ICmpInst::ICMP_EQ, V, + ConstantPointerNull::get(Type), + CS.getInstruction()) == LazyValueInfo::False) { + AttributeSet AS = CS.getAttributes(); + AS = AS.addAttribute(CS.getInstruction()->getContext(), ArgNo + 1, + Attribute::NonNull); + CS.setAttributes(AS); + Changed = true; + } + ArgNo++; + } + assert(ArgNo == CS.arg_size() && "sanity check"); + + return Changed; +} + bool CorrelatedValuePropagation::runOnFunction(Function &F) { if (skipOptnoneFunction(F)) return false; @@ -336,6 +363,10 @@ case Instruction::Store: BBChanged |= processMemAccess(II); break; + case Instruction::Call: + case Instruction::Invoke: + BBChanged |= processCallSite(CallSite(II)); + break; } } Index: llvm/trunk/test/Transforms/CorrelatedValuePropagation/non-null.ll =================================================================== --- llvm/trunk/test/Transforms/CorrelatedValuePropagation/non-null.ll +++ llvm/trunk/test/Transforms/CorrelatedValuePropagation/non-null.ll @@ -101,3 +101,42 @@ ; CHECK: KEEP2 ret void } + +declare void @test10_helper(i8* %arg1, i8* %arg2, i32 %non-pointer-arg) +define void @test10(i8* %arg1, i8* %arg2, i32 %non-pointer-arg) { +; CHECK-LABEL: @test10 +entry: + %is_null = icmp eq i8* %arg1, null + br i1 %is_null, label %null, label %non_null + +non_null: + call void @test10_helper(i8* %arg1, i8* %arg2, i32 %non-pointer-arg) + ; CHECK: call void @test10_helper(i8* nonnull %arg1, i8* %arg2, i32 %non-pointer-arg) + br label %null + +null: + call void @test10_helper(i8* %arg1, i8* %arg2, i32 %non-pointer-arg) + ; CHECK: call void @test10_helper(i8* %arg1, i8* %arg2, i32 %non-pointer-arg) + ret void +} + +declare void @test11_helper(i8* %arg) +define void @test11(i8* %arg1, i8** %arg2) { +; CHECK-LABEL: @test11 +entry: + %is_null = icmp eq i8* %arg1, null + br i1 %is_null, label %null, label %non_null + +non_null: + br label %merge + +null: + %another_arg = alloca i8 + br label %merge + +merge: + %merged_arg = phi i8* [%another_arg, %null], [%arg1, %non_null] + call void @test11_helper(i8* %merged_arg) + ; CHECK: call void @test11_helper(i8* nonnull %merged_arg) + ret void +}