aboutsummaryrefslogtreecommitdiff
path: root/lib/Transforms/NaCl/RewriteLLVMIntrinsics.cpp
blob: 9b3d3cea51688a02f65b9e0dbe0ffb50f0deb034 (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
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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
//===- RewriteLLVMIntrinsics.cpp - Rewrite LLVM intrinsics to other values ===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This pass replaces calls to LLVM intrinsics that are *not* part of the
// PNaCl stable bitcode ABI into simpler values.
//
//===----------------------------------------------------------------------===//

#include "llvm/ADT/Twine.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/Module.h"
#include "llvm/Pass.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/NaCl.h"
#include <string>

using namespace llvm;

namespace {
class RewriteLLVMIntrinsics : public ModulePass {
public:
  static char ID;
  RewriteLLVMIntrinsics() : ModulePass(ID) {
    // This is a module pass because this makes it easier to access uses
    // of global intrinsic functions.
    initializeRewriteLLVMIntrinsicsPass(*PassRegistry::getPassRegistry());
  }

  virtual bool runOnModule(Module &M);

  /// Rewrite an intrinsic to something different.
  class IntrinsicRewriter {
  public:
    Function *function() const { return F; }
    /// Called once per \p Call of the Intrinsic Function.
    void rewriteCall(CallInst *Call) { doRewriteCall(Call); }

  protected:
    IntrinsicRewriter(Module &M, Intrinsic::ID IntrinsicID)
        : F(Intrinsic::getDeclaration(&M, IntrinsicID)) {}
    virtual ~IntrinsicRewriter() {}
    /// This pure virtual method must be defined by implementors, and
    /// will be called by rewriteCall.
    virtual void doRewriteCall(CallInst *Call) = 0;

    Function *F;

  private:
    IntrinsicRewriter() LLVM_DELETED_FUNCTION;
    IntrinsicRewriter(const IntrinsicRewriter &) LLVM_DELETED_FUNCTION;
    IntrinsicRewriter &operator=(
        const IntrinsicRewriter &) LLVM_DELETED_FUNCTION;
  };

private:
  /// Visit all uses of a Function, rewrite it using the \p Rewriter,
  /// and then delete the Call. Later delete the Function from the
  /// Module. Returns true if the Module was changed.
  bool visitUses(IntrinsicRewriter &Rewriter);
};

/// Rewrite a Call to nothing.
class ToNothing : public RewriteLLVMIntrinsics::IntrinsicRewriter {
public:
  ToNothing(Module &M, Intrinsic::ID IntrinsicID)
      : IntrinsicRewriter(M, IntrinsicID) {}
  virtual ~ToNothing() {}

protected:
  virtual void doRewriteCall(CallInst *Call) {
    // Nothing to do: the visit does the deletion.
  }
};

/// Rewrite a Call to a ConstantInt of the same type.
class ToConstantInt : public RewriteLLVMIntrinsics::IntrinsicRewriter {
public:
  ToConstantInt(Module &M, Intrinsic::ID IntrinsicID, uint64_t Value)
      : IntrinsicRewriter(M, IntrinsicID), Value(Value),
        RetType(function()->getFunctionType()->getReturnType()) {}
  virtual ~ToConstantInt() {}

protected:
  virtual void doRewriteCall(CallInst *Call) {
    Constant *C = ConstantInt::get(RetType, Value);
    Call->replaceAllUsesWith(C);
  }

private:
  uint64_t Value;
  Type *RetType;
};
}

char RewriteLLVMIntrinsics::ID = 0;
INITIALIZE_PASS(RewriteLLVMIntrinsics, "rewrite-llvm-intrinsic-calls",
                "Rewrite LLVM intrinsic calls to simpler expressions", false,
                false)

bool RewriteLLVMIntrinsics::runOnModule(Module &M) {
  // Replace all uses of the @llvm.flt.rounds intrinsic with the constant
  // "1" (round-to-nearest). Until we add a second intrinsic like
  // @llvm.set.flt.round it is impossible to have a rounding mode that is
  // not the initial rounding mode (round-to-nearest). We can remove
  // this rewrite after adding a set() intrinsic.
  ToConstantInt FltRoundsRewriter(M, Intrinsic::flt_rounds, 1);

  // Remove all @llvm.prefetch intrinsics.
  ToNothing PrefetchRewriter(M, Intrinsic::prefetch);

  return visitUses(FltRoundsRewriter) | visitUses(PrefetchRewriter);
}

bool RewriteLLVMIntrinsics::visitUses(IntrinsicRewriter &Rewriter) {
  bool Changed = false;
  Function *F = Rewriter.function();
  for (Value::use_iterator UI = F->use_begin(), UE = F->use_end(); UI != UE;) {
    Value *Use = *UI++;
    if (CallInst *Call = dyn_cast<CallInst>(Use)) {
      Rewriter.rewriteCall(Call);
      Call->eraseFromParent();
      Changed = true;
    } else {
      // Intrinsics we care about currently don't need to handle this case.
      std::string S;
      raw_string_ostream OS(S);
      OS << "Taking the address of this intrinsic is invalid: " << *Use;
      report_fatal_error(OS.str());
    }
  }
  F->eraseFromParent();
  return Changed;
}

ModulePass *llvm::createRewriteLLVMIntrinsicsPass() {
  return new RewriteLLVMIntrinsics();
}