//===- ObjCARCInstKind.h - ARC instruction equivalence classes --*- C++ -*-===//
 
//
 
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 
// See https://llvm.org/LICENSE.txt for license information.
 
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 
//
 
//===----------------------------------------------------------------------===//
 
 
 
#ifndef LLVM_ANALYSIS_OBJCARCINSTKIND_H
 
#define LLVM_ANALYSIS_OBJCARCINSTKIND_H
 
 
 
#include "llvm/IR/Instructions.h"
 
 
 
namespace llvm {
 
namespace objcarc {
 
 
 
/// \enum ARCInstKind
 
///
 
/// Equivalence classes of instructions in the ARC Model.
 
///
 
/// Since we do not have "instructions" to represent ARC concepts in LLVM IR,
 
/// we instead operate on equivalence classes of instructions.
 
///
 
/// TODO: This should be split into two enums: a runtime entry point enum
 
/// (possibly united with the ARCRuntimeEntrypoint class) and an enum that deals
 
/// with effects of instructions in the ARC model (which would handle the notion
 
/// of a User or CallOrUser).
 
enum class ARCInstKind {
 
  Retain,                   ///< objc_retain
 
  RetainRV,                 ///< objc_retainAutoreleasedReturnValue
 
  UnsafeClaimRV,            ///< objc_unsafeClaimAutoreleasedReturnValue
 
  RetainBlock,              ///< objc_retainBlock
 
  Release,                  ///< objc_release
 
  Autorelease,              ///< objc_autorelease
 
  AutoreleaseRV,            ///< objc_autoreleaseReturnValue
 
  AutoreleasepoolPush,      ///< objc_autoreleasePoolPush
 
  AutoreleasepoolPop,       ///< objc_autoreleasePoolPop
 
  NoopCast,                 ///< objc_retainedObject, etc.
 
  FusedRetainAutorelease,   ///< objc_retainAutorelease
 
  FusedRetainAutoreleaseRV, ///< objc_retainAutoreleaseReturnValue
 
  LoadWeakRetained,         ///< objc_loadWeakRetained (primitive)
 
  StoreWeak,                ///< objc_storeWeak (primitive)
 
  InitWeak,                 ///< objc_initWeak (derived)
 
  LoadWeak,                 ///< objc_loadWeak (derived)
 
  MoveWeak,                 ///< objc_moveWeak (derived)
 
  CopyWeak,                 ///< objc_copyWeak (derived)
 
  DestroyWeak,              ///< objc_destroyWeak (derived)
 
  StoreStrong,              ///< objc_storeStrong (derived)
 
  IntrinsicUser,            ///< llvm.objc.clang.arc.use
 
  CallOrUser,               ///< could call objc_release and/or "use" pointers
 
  Call,                     ///< could call objc_release
 
  User,                     ///< could "use" a pointer
 
  None                      ///< anything that is inert from an ARC perspective.
 
};
 
 
 
raw_ostream &operator<<(raw_ostream &OS, const ARCInstKind Class);
 
 
 
/// Test if the given class is a kind of user.
 
bool IsUser(ARCInstKind Class);
 
 
 
/// Test if the given class is objc_retain or equivalent.
 
bool IsRetain(ARCInstKind Class);
 
 
 
/// Test if the given class is objc_autorelease or equivalent.
 
bool IsAutorelease(ARCInstKind Class);
 
 
 
/// Test if the given class represents instructions which return their
 
/// argument verbatim.
 
bool IsForwarding(ARCInstKind Class);
 
 
 
/// Test if the given class represents instructions which do nothing if
 
/// passed a null pointer.
 
bool IsNoopOnNull(ARCInstKind Class);
 
 
 
/// Test if the given class represents instructions which do nothing if
 
/// passed a global variable.
 
bool IsNoopOnGlobal(ARCInstKind Class);
 
 
 
/// Test if the given class represents instructions which are always safe
 
/// to mark with the "tail" keyword.
 
bool IsAlwaysTail(ARCInstKind Class);
 
 
 
/// Test if the given class represents instructions which are never safe
 
/// to mark with the "tail" keyword.
 
bool IsNeverTail(ARCInstKind Class);
 
 
 
/// Test if the given class represents instructions which are always safe
 
/// to mark with the nounwind attribute.
 
bool IsNoThrow(ARCInstKind Class);
 
 
 
/// Test whether the given instruction can autorelease any pointer or cause an
 
/// autoreleasepool pop.
 
bool CanInterruptRV(ARCInstKind Class);
 
 
 
/// Determine if F is one of the special known Functions.  If it isn't,
 
/// return ARCInstKind::CallOrUser.
 
ARCInstKind GetFunctionClass(const Function *F);
 
 
 
/// Determine which objc runtime call instruction class V belongs to.
 
///
 
/// This is similar to GetARCInstKind except that it only detects objc
 
/// runtime calls. This allows it to be faster.
 
///
 
inline ARCInstKind GetBasicARCInstKind(const Value *V) {
 
  if (const CallInst *CI = dyn_cast<CallInst>(V)) {
 
    if (const Function *F = CI->getCalledFunction())
 
      return GetFunctionClass(F);
 
    // Otherwise, be conservative.
 
    return ARCInstKind::CallOrUser;
 
  }
 
 
 
  // Otherwise, be conservative.
 
  return isa<InvokeInst>(V) ? ARCInstKind::CallOrUser : ARCInstKind::User;
 
}
 
 
 
/// Map V to its ARCInstKind equivalence class.
 
ARCInstKind GetARCInstKind(const Value *V);
 
 
 
/// Returns false if conservatively we can prove that any instruction mapped to
 
/// this kind can not decrement ref counts. Returns true otherwise.
 
bool CanDecrementRefCount(ARCInstKind Kind);
 
 
 
} // end namespace objcarc
 
} // end namespace llvm
 
 
 
#endif