Index: lib/Analysis/BasicAliasAnalysis.cpp =================================================================== --- lib/Analysis/BasicAliasAnalysis.cpp +++ lib/Analysis/BasicAliasAnalysis.cpp @@ -530,23 +530,6 @@ return Worklist.empty(); } -// FIXME: This code is duplicated with MemoryLocation and should be hoisted to -// some common utility location. -static bool isMemsetPattern16(const Function *MS, - const TargetLibraryInfo &TLI) { - if (TLI.has(LibFunc::memset_pattern16) && - MS->getName() == "memset_pattern16") { - FunctionType *MemsetType = MS->getFunctionType(); - if (!MemsetType->isVarArg() && MemsetType->getNumParams() == 3 && - isa(MemsetType->getParamType(0)) && - isa(MemsetType->getParamType(1)) && - isa(MemsetType->getParamType(2))) - return true; - } - - return false; -} - /// Returns the behavior when calling the given call site. FunctionModRefBehavior BasicAAResult::getModRefBehavior(ImmutableCallSite CS) { if (CS.doesNotAccessMemory()) @@ -583,9 +566,6 @@ if (F->onlyAccessesArgMemory()) Min = FunctionModRefBehavior(Min & FMRB_OnlyAccessesArgumentPointees); - if (isMemsetPattern16(F, TLI)) - Min = FMRB_OnlyAccessesArgumentPointees; - // Otherwise be conservative. return FunctionModRefBehavior(AAResultBase::getModRefBehavior(F) & Min); } @@ -604,18 +584,6 @@ return ArgIdx ? MRI_Ref : MRI_Mod; } - // We can bound the aliasing properties of memset_pattern16 just as we can - // for memcpy/memset. This is particularly important because the - // LoopIdiomRecognizer likes to turn loops into calls to memset_pattern16 - // whenever possible. - if (CS.getCalledFunction() && - isMemsetPattern16(CS.getCalledFunction(), TLI)) { - assert((ArgIdx == 0 || ArgIdx == 1) && - "Invalid argument index for memset_pattern16"); - return ArgIdx ? MRI_Ref : MRI_Mod; - } - // FIXME: Handle memset_pattern4 and memset_pattern8 also. - if (CS.paramHasAttr(ArgIdx + 1, Attribute::ReadOnly)) return MRI_Ref; Index: lib/Transforms/IPO/InferFunctionAttrs.cpp =================================================================== --- lib/Transforms/IPO/InferFunctionAttrs.cpp +++ lib/Transforms/IPO/InferFunctionAttrs.cpp @@ -22,6 +22,7 @@ STATISTIC(NumReadNone, "Number of functions inferred as readnone"); STATISTIC(NumReadOnly, "Number of functions inferred as readonly"); +STATISTIC(NumArgMemOnly, "Number of functions inferred as argmemonly"); STATISTIC(NumNoUnwind, "Number of functions inferred as nounwind"); STATISTIC(NumNoCapture, "Number of arguments inferred as nocapture"); STATISTIC(NumReadOnlyArg, "Number of arguments inferred as readonly"); @@ -44,6 +45,15 @@ return true; } +static bool setOnlyAccessesArgMemory(Function &F) { + if (F.onlyAccessesArgMemory()) + return false; + F.setOnlyAccessesArgMemory (); + ++NumArgMemOnly; + return true; +} + + static bool setDoesNotThrow(Function &F) { if (F.doesNotThrow()) return false; @@ -900,6 +910,20 @@ Changed |= setDoesNotAlias(F, AttributeSet::ReturnIndex); return Changed; + //TODO: add LibFunc entries for: + //case LibFunc::memset_pattern4: + //case LibFunc::memset_pattern8: + case LibFunc::memset_pattern16: + if (FTy->isVarArg() || FTy->getNumParams() != 3 || + !isa(FTy->getParamType(0)) || + !isa(FTy->getParamType(1)) || + !isa(FTy->getParamType(2))) + return false; + + Changed |= setOnlyAccessesArgMemory(F); + Changed |= setOnlyReadsMemory(F, 2); + return Changed; + default: // FIXME: It'd be really nice to cover all the library functions we're // aware of here. Index: test/Analysis/BasicAA/memset_pattern.ll =================================================================== --- test/Analysis/BasicAA/memset_pattern.ll +++ test/Analysis/BasicAA/memset_pattern.ll @@ -18,4 +18,4 @@ ret i32 %l } -declare void @memset_pattern16(i8*, i8*, i64) +declare void @memset_pattern16(i8*, i8* readonly, i64) argmemonly Index: test/Transforms/InferFunctionAttrs/annotate.ll =================================================================== --- test/Transforms/InferFunctionAttrs/annotate.ll +++ test/Transforms/InferFunctionAttrs/annotate.ll @@ -22,9 +22,14 @@ declare i8* @_Znwm(i64) ; CHECK: declare noalias nonnull i8* @_Znwm(i64) +declare void @memset_pattern16(i8*, i8*, i64) +; CHECK: declare void @memset_pattern16(i8*, i8*, i64) +; CHECK-POSIX: declare void @memset_pattern16(i8*, i8* readonly, i64) [[G2:#[0-9]+]] + declare i32 @gettimeofday(i8*, i8*) ; CHECK-POSIX: declare i32 @gettimeofday(i8* nocapture, i8* nocapture) [[G0:#[0-9]+]] ; CHECK: attributes [[G0]] = { nounwind } ; CHECK: attributes [[G1]] = { nounwind readonly } ; CHECK-POSIX: attributes [[G0]] = { nounwind } +; CHECK-POSIX: attributes [[G2]] = { argmemonly }