summaryrefslogtreecommitdiffstats
path: root/llvm/lib/Analysis/BitSetUtils.cpp
blob: d83dca60cceaa49cefc77f0f3575d473a1ff5967 (plain)
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
//===- BitSetUtils.cpp - Utilities related to pointer bitsets -------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains functions that make it easier to manipulate bitsets for
// devirtualization.
//
//===----------------------------------------------------------------------===//

#include "llvm/Analysis/BitSetUtils.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/Module.h"

using namespace llvm;

// Search for virtual calls that call FPtr and add them to DevirtCalls.
static void
findCallsAtConstantOffset(SmallVectorImpl<DevirtCallSite> &DevirtCalls,
                          Value *FPtr, uint64_t Offset) {
  for (const Use &U : FPtr->uses()) {
    Value *User = U.getUser();
    if (isa<BitCastInst>(User)) {
      findCallsAtConstantOffset(DevirtCalls, User, Offset);
    } else if (auto CI = dyn_cast<CallInst>(User)) {
      DevirtCalls.push_back({Offset, CI});
    } else if (auto II = dyn_cast<InvokeInst>(User)) {
      DevirtCalls.push_back({Offset, II});
    }
  }
}

// Search for virtual calls that load from VPtr and add them to DevirtCalls.
static void
findLoadCallsAtConstantOffset(Module *M,
                              SmallVectorImpl<DevirtCallSite> &DevirtCalls,
                              Value *VPtr, uint64_t Offset) {
  for (const Use &U : VPtr->uses()) {
    Value *User = U.getUser();
    if (isa<BitCastInst>(User)) {
      findLoadCallsAtConstantOffset(M, DevirtCalls, User, Offset);
    } else if (isa<LoadInst>(User)) {
      findCallsAtConstantOffset(DevirtCalls, User, Offset);
    } else if (auto GEP = dyn_cast<GetElementPtrInst>(User)) {
      // Take into account the GEP offset.
      if (VPtr == GEP->getPointerOperand() && GEP->hasAllConstantIndices()) {
        SmallVector<Value *, 8> Indices(GEP->op_begin() + 1, GEP->op_end());
        uint64_t GEPOffset = M->getDataLayout().getIndexedOffsetInType(
            GEP->getSourceElementType(), Indices);
        findLoadCallsAtConstantOffset(M, DevirtCalls, User, Offset + GEPOffset);
      }
    }
  }
}

void llvm::findDevirtualizableCalls(
    SmallVectorImpl<DevirtCallSite> &DevirtCalls,
    SmallVectorImpl<CallInst *> &Assumes, CallInst *CI) {
  assert(CI->getCalledFunction()->getIntrinsicID() == Intrinsic::bitset_test);

  Module *M = CI->getParent()->getParent()->getParent();

  // Find llvm.assume intrinsics for this llvm.bitset.test call.
  for (const Use &CIU : CI->uses()) {
    auto AssumeCI = dyn_cast<CallInst>(CIU.getUser());
    if (AssumeCI) {
      Function *F = AssumeCI->getCalledFunction();
      if (F && F->getIntrinsicID() == Intrinsic::assume)
        Assumes.push_back(AssumeCI);
    }
  }

  // If we found any, search for virtual calls based on %p and add them to
  // DevirtCalls.
  if (!Assumes.empty())
    findLoadCallsAtConstantOffset(M, DevirtCalls,
                                  CI->getArgOperand(0)->stripPointerCasts(), 0);
}
OpenPOWER on IntegriCloud