Index: llvm/trunk/lib/Analysis/BasicAliasAnalysis.cpp =================================================================== --- llvm/trunk/lib/Analysis/BasicAliasAnalysis.cpp +++ llvm/trunk/lib/Analysis/BasicAliasAnalysis.cpp @@ -543,7 +543,6 @@ isa(MemsetType->getParamType(2))) return true; } - return false; } @@ -583,9 +582,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); } @@ -609,14 +605,11 @@ // 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. + // whenever possible. Note that all but the missing writeonly attribute are + // handled via InferFunctionAttr. + if (CS.getCalledFunction() && isMemsetPattern16(CS.getCalledFunction(), TLI)) + if (ArgIdx == 0) + return MRI_Mod; if (CS.paramHasAttr(ArgIdx + 1, Attribute::ReadOnly)) return MRI_Ref; Index: llvm/trunk/lib/Transforms/IPO/InferFunctionAttrs.cpp =================================================================== --- llvm/trunk/lib/Transforms/IPO/InferFunctionAttrs.cpp +++ llvm/trunk/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: llvm/trunk/test/Analysis/BasicAA/memset_pattern.ll =================================================================== --- llvm/trunk/test/Analysis/BasicAA/memset_pattern.ll +++ llvm/trunk/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: llvm/trunk/test/Transforms/InferFunctionAttrs/annotate.ll =================================================================== --- llvm/trunk/test/Transforms/InferFunctionAttrs/annotate.ll +++ llvm/trunk/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 }