reference, declarationdefinition
definition → references, declarations, derived classes, virtual overrides
reference to multiple definitions → definitions
unreferenced
    1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
//===- 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/Function.h"
#include "llvm/IR/Intrinsics.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
  ClaimRV,                  ///< 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