aboutsummaryrefslogtreecommitdiff
path: root/lib/Transforms/NaCl/ResolvePNaClIntrinsics.cpp
blob: e4efeb67c3c3c24c5ca1103f960338dea0c134f6 (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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
//===- ResolvePNaClIntrinsics.cpp - Resolve calls to PNaCl intrinsics ----====//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This pass resolves calls to PNaCl stable bitcode intrinsics. It is
// normally run in the PNaCl translator.
//
// Running AddPNaClExternalDeclsPass is a precondition for running this pass.
// They are separate because one is a ModulePass and the other is a
// FunctionPass.
//
//===----------------------------------------------------------------------===//

#include "llvm/ADT/SmallVector.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/Module.h"
#include "llvm/Pass.h"
#include "llvm/Transforms/NaCl.h"

using namespace llvm;

namespace {
  class ResolvePNaClIntrinsics : public FunctionPass {
  public:
    ResolvePNaClIntrinsics() : FunctionPass(ID) {
      initializeResolvePNaClIntrinsicsPass(*PassRegistry::getPassRegistry());
    }

    static char ID;
    virtual bool runOnFunction(Function &F);
  private:
    // Some intrinsic calls are resolved simply by replacing the call with a
    // call to an alternative function with exactly the same type.
    bool resolveSimpleCall(Function &F, Intrinsic::ID IntrinsicID,
                           const char *TargetFunctionName);
  };
}

bool ResolvePNaClIntrinsics::resolveSimpleCall(Function &F,
                                               Intrinsic::ID IntrinsicID,
                                               const char *TargetFunctionName) {
  Module *M = F.getParent();
  bool Changed = false;
  Function *IntrinsicFunction = Intrinsic::getDeclaration(M, IntrinsicID);

  if (!IntrinsicFunction) {
    return false;
  }

  // Expect to find the target function for this intrinsic already declared
  Function *TargetFunction = M->getFunction(TargetFunctionName);
  if (!TargetFunction) {
    report_fatal_error(
        std::string("Expected to find external declaration of ") +
        TargetFunctionName);
  }

  for (Value::use_iterator UI = IntrinsicFunction->use_begin(),
                           UE = IntrinsicFunction->use_end(); UI != UE;) {
    // At this point, the only uses of the intrinsic can be calls, since
    // we assume this pass runs on bitcode that passed ABI verification.
    CallInst *Call = dyn_cast<CallInst>(*UI++);

    if (!Call) {
      report_fatal_error(
          std::string("Expected use of intrinsic to be a call: ") +
          Intrinsic::getName(IntrinsicID));
    }

    // To be a well-behaving FunctionPass, don't touch uses in other
    // functions. These will be handled when the pass manager gets to those
    // functions.
    if (Call->getParent()->getParent() == &F) {
      Call->setCalledFunction(TargetFunction);
      Changed = true;
    }
  }

  return Changed;
}

bool ResolvePNaClIntrinsics::runOnFunction(Function &F) {
  bool Changed = resolveSimpleCall(F, Intrinsic::nacl_setjmp, "setjmp");
  Changed |= resolveSimpleCall(F, Intrinsic::nacl_longjmp, "longjmp");
  return Changed;
}

char ResolvePNaClIntrinsics::ID = 0;
INITIALIZE_PASS(ResolvePNaClIntrinsics, "resolve-pnacl-intrinsics",
                "Resolve PNaCl intrinsic calls", false, false)

FunctionPass *llvm::createResolvePNaClIntrinsicsPass() {
  return new ResolvePNaClIntrinsics();
}