Index: llvm/include/llvm/IR/Attributes.td =================================================================== --- llvm/include/llvm/IR/Attributes.td +++ llvm/include/llvm/IR/Attributes.td @@ -202,6 +202,10 @@ /// Zero extended before/after call. def ZExt : EnumAttr<"zeroext">; +/// No Free Call +/// This is an experimental attribute. +def NoFree : StrBoolAttr<"nofree">; + /// Target-independent string attributes. def LessPreciseFPMAD : StrBoolAttr<"less-precise-fpmad">; def NoInfsFPMath : StrBoolAttr<"no-infs-fp-math">; Index: llvm/lib/Transforms/IPO/Attributor.cpp =================================================================== --- llvm/lib/Transforms/IPO/Attributor.cpp +++ llvm/lib/Transforms/IPO/Attributor.cpp @@ -50,6 +50,8 @@ STATISTIC(NumFnArgumentReturned, "Number of function arguments marked returned"); +STATISTIC(NumFnNoFree, "Number of function marked nofree"); + // TODO: Determine a good default value. // // In the LLVM-TS and SPEC2006, 32 seems to not induce compile time overheads @@ -179,6 +181,14 @@ if (!AreStatisticsEnabled()) return; + if (Attr.isStringAttribute()) { + StringRef StringAttr = Attr.getKindAsString(); + if (StringAttr == "nofree") { + NumFnNoFree++; + } + return; + } + if (!Attr.isEnumAttribute()) return; switch (Attr.getKindAsEnum()) { @@ -700,6 +710,82 @@ return Changed; } +/// ------------------------ No-Free Attributes ---------------------------- + +struct AANoFreeFunction : AbstractAttribute, BooleanState { + + /// See AbstractAttribute::AbstractAttribute(...). + AANoFreeFunction(Function &F, InformationCache &InfoCache) + : AbstractAttribute(F, InfoCache) {} + + /// See AbstractAttribute::getState() + ///{ + AbstractState &getState() override { return *this; } + const AbstractState &getState() const override { return *this; } + ///} + + /// See AbstractAttribute::getManifestPosition(). + virtual ManifestPosition getManifestPosition() const override { + return MP_FUNCTION; + } + + /// See AbstractAttribute::getAsStr(). + virtual const std::string getAsStr() const override { + return getAssumed() ? "nofree" : "may-free"; + } + + /// See AbstractAttribute::updateImpl(...). + virtual ChangeStatus updateImpl(Attributor &A) override; + + /// Return the deduced attributes in \p Attrs. + virtual void + getDeducedAttributes(SmallVectorImpl &Attrs) const override { + LLVMContext &Ctx = AnchoredVal.getContext(); + Attrs.emplace_back(Attribute::get(Ctx, "nofree")); + } + + /// See AbstractAttribute::getAttrKind(). + virtual Attribute::AttrKind getAttrKind() const override { + return Attribute::None; + } + + /// Return true if "nofree" is assumed. + bool isAssumedNoFree() const { return getAssumed(); } + + /// Return true if "nofree" is known. + bool isKnownNoFree() const { return getKnown(); } + + /// FIXME: I tried ((AttrKind) - 2) for ID but I got exception so I use + /// Attribute::None + 1 for now. + static constexpr Attribute::AttrKind ID = + Attribute::AttrKind(Attribute::None + 1); +}; + +ChangeStatus AANoFreeFunction::updateImpl(Attributor &A) { + Function &F = getAnchorScope(); + + // The map from instruction opcodes to those instructions in the function. + auto &OpcodeInstMap = InfoCache.getOpcodeInstMapForFunction(F); + + for (unsigned Opcode : + {(unsigned)Instruction::Invoke, (unsigned)Instruction::CallBr, + (unsigned)Instruction::Call}) { + for (Instruction *I : OpcodeInstMap[Opcode]) { + // Assume that all intrinsic function wouldn't free memory. + if (isa(I)) { + continue; + } + auto *NoFreeAA = A.getAAFor(*this, *I); + if (!NoFreeAA || !NoFreeAA->isValidState() || + !NoFreeAA->isAssumedNoFree()) { + indicatePessimisticFixpoint(); + return ChangeStatus::CHANGED; + } + } + } + return ChangeStatus::UNCHANGED; +} + /// ---------------------------------------------------------------------------- /// Attributor /// ---------------------------------------------------------------------------- @@ -849,6 +935,9 @@ registerAA(*new AAReturnedValuesImpl(F, InfoCache)); } + // Every function might be "no-free". + registerAA(*new AANoFreeFunction(F, InfoCache)); + // Walk all instructions to find more attribute opportunities and also // interesting instructions that might be queried by abstract attributes // during their initialization or update. @@ -860,7 +949,14 @@ switch (I.getOpcode()) { default: + assert((!ImmutableCallSite(&I)) && (!isa(&I)) && + "New call site/base instruction type needs to be known in the " + "attributor!"); break; + case Instruction::Call: + case Instruction::CallBr: + case Instruction::Invoke: + // Call-like instructions are interesting for AANoFreeFunction. case Instruction::Ret: // ReturnInst are interesting for AAReturnedValues. IsInterestingOpcode = true; }