Skip to content

Commit

Permalink
Add writeonly IR attribute
Browse files Browse the repository at this point in the history
Summary:
This complements the earlier addition of IntrWriteMem and IntrWriteArgMem
LLVM intrinsic properties, see D18291.

Also start using the attribute for memset, memcpy, and memmove intrinsics,
and remove their special-casing in BasicAliasAnalysis.

Reviewers: reames, joker.eph

Subscribers: joker.eph, llvm-commits

Differential Revision: http://reviews.llvm.org/D18714

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@274485 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
nhaehnle committed Jul 4, 2016
1 parent 061feda commit b07f540
Show file tree
Hide file tree
Showing 30 changed files with 194 additions and 48 deletions.
7 changes: 7 additions & 0 deletions docs/LangRef.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1474,6 +1474,13 @@ example:
On an argument, this attribute indicates that the function does not write
through this pointer argument, even though it may write to the memory that
the pointer points to.
``writeonly``
On a function, this attribute indicates that the function may write to but
does not read from memory.

On an argument, this attribute indicates that the function may write to but
does not read through this pointer argument (even though it may read from
the memory that the pointer points to).
``argmemonly``
This attribute indicates that the only memory accesses inside function are
loads and stores from objects pointed to by its pointer-typed arguments,
Expand Down
13 changes: 13 additions & 0 deletions include/llvm/Analysis/AliasAnalysis.h
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,13 @@ enum FunctionModRefBehavior {
/// This property corresponds to the IntrReadMem LLVM intrinsic flag.
FMRB_OnlyReadsMemory = FMRL_Anywhere | MRI_Ref,

// This function does not read from memory anywhere, but may write to any
// memory location.
//
// This property corresponds to the LLVM IR 'writeonly' attribute.
// This property corresponds to the IntrWriteMem LLVM intrinsic flag.
FMRB_DoesNotReadMemory = FMRL_Anywhere | MRI_Mod,

/// This indicates that the function could not be classified into one of the
/// behaviors above.
FMRB_UnknownModRefBehavior = FMRL_Anywhere | MRI_ModRef
Expand Down Expand Up @@ -312,6 +319,12 @@ class AAResults {
return !(MRB & MRI_Mod);
}

/// Checks if functions with the specified behavior are known to only write
/// memory (or not access memory at all).
static bool doesNotReadMemory(FunctionModRefBehavior MRB) {
return !(MRB & MRI_Ref);
}

/// Checks if functions with the specified behavior are known to read and
/// write at most from objects pointed to by their pointer-typed arguments
/// (with arbitrary offsets).
Expand Down
3 changes: 2 additions & 1 deletion include/llvm/Bitcode/LLVMBitCodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -521,7 +521,8 @@ enum AttributeKindCodes {
ATTR_KIND_NO_RECURSE = 48,
ATTR_KIND_INACCESSIBLEMEM_ONLY = 49,
ATTR_KIND_INACCESSIBLEMEM_OR_ARGMEMONLY = 50,
ATTR_KIND_ALLOC_SIZE = 51
ATTR_KIND_ALLOC_SIZE = 51,
ATTR_KIND_WRITEONLY = 52
};

enum ComdatSelectionKindCodes {
Expand Down
3 changes: 3 additions & 0 deletions include/llvm/IR/Attributes.td
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,9 @@ def SwiftSelf : EnumAttr<"swiftself">;
/// Function must be in a unwind table.
def UWTable : EnumAttr<"uwtable">;

/// Function only writes to memory.
def WriteOnly : EnumAttr<"writeonly">;

/// Zero extended before/after call.
def ZExt : EnumAttr<"zeroext">;

Expand Down
8 changes: 8 additions & 0 deletions include/llvm/IR/CallSite.h
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,14 @@ class CallSiteBase {
CALLSITE_DELEGATE_SETTER(setOnlyReadsMemory());
}

/// @brief Determine if the call does not access or only writes memory.
bool doesNotReadMemory() const {
CALLSITE_DELEGATE_GETTER(doesNotReadMemory());
}
void setDoesNotReadMemory() {
CALLSITE_DELEGATE_SETTER(setDoesNotReadMemory());
}

/// @brief Determine if the call can access memmory only using pointers based
/// on its arguments.
bool onlyAccessesArgMemory() const {
Expand Down
8 changes: 8 additions & 0 deletions include/llvm/IR/Function.h
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,14 @@ class Function : public GlobalObject, public ilist_node<Function> {
addFnAttr(Attribute::ReadOnly);
}

/// @brief Determine if the function does not access or only writes memory.
bool doesNotReadMemory() const {
return doesNotAccessMemory() || hasFnAttribute(Attribute::WriteOnly);
}
void setDoesNotReadMemory() {
addFnAttr(Attribute::WriteOnly);
}

/// @brief Determine if the call can access memmory only using pointers based
/// on its arguments.
bool onlyAccessesArgMemory() const {
Expand Down
16 changes: 16 additions & 0 deletions include/llvm/IR/Instructions.h
Original file line number Diff line number Diff line change
Expand Up @@ -1739,6 +1739,14 @@ class CallInst : public Instruction,
addAttribute(AttributeSet::FunctionIndex, Attribute::ReadOnly);
}

/// \brief Determine if the call does not access or only writes memory.
bool doesNotReadMemory() const {
return doesNotAccessMemory() || hasFnAttr(Attribute::WriteOnly);
}
void setDoesNotReadMemory() {
addAttribute(AttributeSet::FunctionIndex, Attribute::WriteOnly);
}

/// @brief Determine if the call can access memmory only using pointers based
/// on its arguments.
bool onlyAccessesArgMemory() const {
Expand Down Expand Up @@ -3691,6 +3699,14 @@ class InvokeInst : public TerminatorInst,
addAttribute(AttributeSet::FunctionIndex, Attribute::ReadOnly);
}

/// \brief Determine if the call does not access or only writes memory.
bool doesNotReadMemory() const {
return doesNotAccessMemory() || hasFnAttr(Attribute::WriteOnly);
}
void setDoesNotReadMemory() {
addAttribute(AttributeSet::FunctionIndex, Attribute::WriteOnly);
}

/// @brief Determine if the call access memmory only using it's pointer
/// arguments.
bool onlyAccessesArgMemory() const {
Expand Down
10 changes: 8 additions & 2 deletions include/llvm/IR/Intrinsics.td
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,12 @@ class ReadOnly<int argNo> : IntrinsicProperty {
int ArgNo = argNo;
}

// WriteOnly - The intrinsic does not read memory through the specified
// argument pointer.
class WriteOnly<int argNo> : IntrinsicProperty {
int ArgNo = argNo;
}

// ReadNone - The specified argument pointer is not dereferenced by the
// intrinsic.
class ReadNone<int argNo> : IntrinsicProperty {
Expand Down Expand Up @@ -349,7 +355,7 @@ def int_memcpy : Intrinsic<[],
[llvm_anyptr_ty, llvm_anyptr_ty, llvm_anyint_ty,
llvm_i32_ty, llvm_i1_ty],
[IntrArgMemOnly, NoCapture<0>, NoCapture<1>,
ReadOnly<1>]>;
WriteOnly<0>, ReadOnly<1>]>;
def int_memmove : Intrinsic<[],
[llvm_anyptr_ty, llvm_anyptr_ty, llvm_anyint_ty,
llvm_i32_ty, llvm_i1_ty],
Expand All @@ -358,7 +364,7 @@ def int_memmove : Intrinsic<[],
def int_memset : Intrinsic<[],
[llvm_anyptr_ty, llvm_i8_ty, llvm_anyint_ty,
llvm_i32_ty, llvm_i1_ty],
[IntrArgMemOnly, NoCapture<0>]>;
[IntrArgMemOnly, NoCapture<0>, WriteOnly<0>]>;

let IntrProperties = [IntrNoMem] in {
def int_fma : Intrinsic<[llvm_anyfloat_ty],
Expand Down
4 changes: 4 additions & 0 deletions lib/Analysis/AliasAnalysis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,8 @@ ModRefInfo AAResults::getModRefInfo(ImmutableCallSite CS,

if (onlyReadsMemory(MRB))
Result = ModRefInfo(Result & MRI_Ref);
else if (doesNotReadMemory(MRB))
Result = ModRefInfo(Result & MRI_Mod);

if (onlyAccessesArgPointees(MRB)) {
bool DoesAlias = false;
Expand Down Expand Up @@ -207,6 +209,8 @@ ModRefInfo AAResults::getModRefInfo(ImmutableCallSite CS1,
// from CS1 reading memory written by CS2.
if (onlyReadsMemory(CS1B))
Result = ModRefInfo(Result & MRI_Ref);
else if (doesNotReadMemory(CS1B))
Result = ModRefInfo(Result & MRI_Mod);

// If CS2 only access memory through arguments, accumulate the mod/ref
// information from CS1's references to the memory referenced by
Expand Down
33 changes: 11 additions & 22 deletions lib/Analysis/BasicAliasAnalysis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -563,6 +563,8 @@ FunctionModRefBehavior BasicAAResult::getModRefBehavior(ImmutableCallSite CS) {
// than that.
if (CS.onlyReadsMemory())
Min = FMRB_OnlyReadsMemory;
else if (CS.doesNotReadMemory())
Min = FMRB_DoesNotReadMemory;

if (CS.onlyAccessesArgMemory())
Min = FunctionModRefBehavior(Min & FMRB_OnlyAccessesArgumentPointees);
Expand Down Expand Up @@ -590,39 +592,27 @@ FunctionModRefBehavior BasicAAResult::getModRefBehavior(const Function *F) {
// If the function declares it only reads memory, go with that.
if (F->onlyReadsMemory())
Min = FMRB_OnlyReadsMemory;
else if (F->doesNotReadMemory())
Min = FMRB_DoesNotReadMemory;

if (F->onlyAccessesArgMemory())
Min = FunctionModRefBehavior(Min & FMRB_OnlyAccessesArgumentPointees);

return Min;
}

/// Returns true if this is a writeonly (i.e Mod only) parameter. Currently,
/// we don't have a writeonly attribute, so this only knows about builtin
/// intrinsics and target library functions. We could consider adding a
/// writeonly attribute in the future and moving all of these facts to either
/// Intrinsics.td or InferFunctionAttr.cpp
/// Returns true if this is a writeonly (i.e Mod only) parameter.
static bool isWriteOnlyParam(ImmutableCallSite CS, unsigned ArgIdx,
const TargetLibraryInfo &TLI) {
if (const IntrinsicInst *II = dyn_cast<IntrinsicInst>(CS.getInstruction()))
switch (II->getIntrinsicID()) {
default:
break;
case Intrinsic::memset:
case Intrinsic::memcpy:
case Intrinsic::memmove:
// We don't currently have a writeonly attribute. All other properties
// of these intrinsics are nicely described via attributes in
// Intrinsics.td and handled generically.
if (ArgIdx == 0)
return true;
}
if (CS.paramHasAttr(ArgIdx + 1, Attribute::WriteOnly))
return true;

// 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. Note that all but the missing writeonly attribute are
// handled via InferFunctionAttr.
// whenever possible.
// FIXME Consider handling this in InferFunctionAttr.cpp together with other
// attributes.
LibFunc::Func F;
if (CS.getCalledFunction() && TLI.getLibFunc(*CS.getCalledFunction(), F) &&
F == LibFunc::memset_pattern16 && TLI.has(F))
Expand All @@ -639,8 +629,7 @@ static bool isWriteOnlyParam(ImmutableCallSite CS, unsigned ArgIdx,
ModRefInfo BasicAAResult::getArgModRefInfo(ImmutableCallSite CS,
unsigned ArgIdx) {

// Emulate the missing writeonly attribute by checking for known builtin
// intrinsics and target library functions.
// Checking for known builtin intrinsics and target library functions.
if (isWriteOnlyParam(CS, ArgIdx, TLI))
return MRI_Mod;

Expand Down
1 change: 1 addition & 0 deletions lib/AsmParser/LLLexer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -660,6 +660,7 @@ lltok::Kind LLLexer::LexIdentifier() {
KEYWORD(swifterror);
KEYWORD(swiftself);
KEYWORD(uwtable);
KEYWORD(writeonly);
KEYWORD(zeroext);

KEYWORD(type);
Expand Down
2 changes: 2 additions & 0 deletions lib/AsmParser/LLParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1098,6 +1098,7 @@ bool LLParser::ParseFnAttributeValuePairs(AttrBuilder &B,
case lltok::kw_sanitize_memory:
B.addAttribute(Attribute::SanitizeMemory); break;
case lltok::kw_uwtable: B.addAttribute(Attribute::UWTable); break;
case lltok::kw_writeonly: B.addAttribute(Attribute::WriteOnly); break;

// Error handling.
case lltok::kw_inreg:
Expand Down Expand Up @@ -1394,6 +1395,7 @@ bool LLParser::ParseOptionalParamAttrs(AttrBuilder &B) {
case lltok::kw_sret: B.addAttribute(Attribute::StructRet); break;
case lltok::kw_swifterror: B.addAttribute(Attribute::SwiftError); break;
case lltok::kw_swiftself: B.addAttribute(Attribute::SwiftSelf); break;
case lltok::kw_writeonly: B.addAttribute(Attribute::WriteOnly); break;
case lltok::kw_zeroext: B.addAttribute(Attribute::ZExt); break;

case lltok::kw_alignstack:
Expand Down
1 change: 1 addition & 0 deletions lib/AsmParser/LLToken.h
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,7 @@ enum Kind {
kw_swifterror,
kw_swiftself,
kw_uwtable,
kw_writeonly,
kw_zeroext,

kw_type,
Expand Down
2 changes: 2 additions & 0 deletions lib/Bitcode/Reader/BitcodeReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1464,6 +1464,8 @@ static Attribute::AttrKind getAttrFromCode(uint64_t Code) {
return Attribute::SwiftSelf;
case bitc::ATTR_KIND_UW_TABLE:
return Attribute::UWTable;
case bitc::ATTR_KIND_WRITEONLY:
return Attribute::WriteOnly;
case bitc::ATTR_KIND_Z_EXT:
return Attribute::ZExt;
}
Expand Down
2 changes: 2 additions & 0 deletions lib/Bitcode/Writer/BitcodeWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -667,6 +667,8 @@ static uint64_t getAttrKindEncoding(Attribute::AttrKind Kind) {
return bitc::ATTR_KIND_SWIFT_SELF;
case Attribute::UWTable:
return bitc::ATTR_KIND_UW_TABLE;
case Attribute::WriteOnly:
return bitc::ATTR_KIND_WRITEONLY;
case Attribute::ZExt:
return bitc::ATTR_KIND_Z_EXT;
case Attribute::EndAttrKinds:
Expand Down
3 changes: 3 additions & 0 deletions lib/IR/Attributes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,8 @@ std::string Attribute::getAsString(bool InAttrGrp) const {
return "readnone";
if (hasAttribute(Attribute::ReadOnly))
return "readonly";
if (hasAttribute(Attribute::WriteOnly))
return "writeonly";
if (hasAttribute(Attribute::Returned))
return "returned";
if (hasAttribute(Attribute::ReturnsTwice))
Expand Down Expand Up @@ -516,6 +518,7 @@ uint64_t AttributeImpl::getAttrMask(Attribute::AttrKind Val) {
case Attribute::InaccessibleMemOrArgMemOnly: return 1ULL << 50;
case Attribute::SwiftSelf: return 1ULL << 51;
case Attribute::SwiftError: return 1ULL << 52;
case Attribute::WriteOnly: return 1ULL << 53;
case Attribute::Dereferenceable:
llvm_unreachable("dereferenceable attribute not supported in raw format");
break;
Expand Down
23 changes: 23 additions & 0 deletions lib/IR/Verifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1309,6 +1309,7 @@ void Verifier::verifyAttributeTypes(AttributeSet Attrs, unsigned Idx,
return;
}
} else if (I->getKindAsEnum() == Attribute::ReadOnly ||
I->getKindAsEnum() == Attribute::WriteOnly ||
I->getKindAsEnum() == Attribute::ReadNone) {
if (Idx == 0) {
CheckFailed("Attribute '" + I->getAsString() +
Expand Down Expand Up @@ -1382,6 +1383,18 @@ void Verifier::verifyParameterAttrs(AttributeSet Attrs, unsigned Idx, Type *Ty,
"'readnone and readonly' are incompatible!",
V);

Assert(!(Attrs.hasAttribute(Idx, Attribute::ReadNone) &&
Attrs.hasAttribute(Idx, Attribute::WriteOnly)),
"Attributes "
"'readnone and writeonly' are incompatible!",
V);

Assert(!(Attrs.hasAttribute(Idx, Attribute::ReadOnly) &&
Attrs.hasAttribute(Idx, Attribute::WriteOnly)),
"Attributes "
"'readonly and writeonly' are incompatible!",
V);

Assert(!(Attrs.hasAttribute(Idx, Attribute::NoInline) &&
Attrs.hasAttribute(Idx, Attribute::AlwaysInline)),
"Attributes "
Expand Down Expand Up @@ -1497,6 +1510,16 @@ void Verifier::verifyFunctionAttrs(FunctionType *FT, AttributeSet Attrs,
Attrs.hasAttribute(AttributeSet::FunctionIndex, Attribute::ReadOnly)),
"Attributes 'readnone and readonly' are incompatible!", V);

Assert(
!(Attrs.hasAttribute(AttributeSet::FunctionIndex, Attribute::ReadNone) &&
Attrs.hasAttribute(AttributeSet::FunctionIndex, Attribute::WriteOnly)),
"Attributes 'readnone and writeonly' are incompatible!", V);

Assert(
!(Attrs.hasAttribute(AttributeSet::FunctionIndex, Attribute::ReadOnly) &&
Attrs.hasAttribute(AttributeSet::FunctionIndex, Attribute::WriteOnly)),
"Attributes 'readonly and writeonly' are incompatible!", V);

Assert(
!(Attrs.hasAttribute(AttributeSet::FunctionIndex, Attribute::ReadNone) &&
Attrs.hasAttribute(AttributeSet::FunctionIndex,
Expand Down
Loading

0 comments on commit b07f540

Please sign in to comment.