1//===-- PreISelIntrinsicLowering.cpp - Pre-ISel intrinsic lowering pass ---===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This pass implements IR lowering for the llvm.load.relative intrinsic.
11//
12//===----------------------------------------------------------------------===//
13
14#include "llvm/CodeGen/PreISelIntrinsicLowering.h"
15#include "llvm/CodeGen/Passes.h"
16#include "llvm/IR/Function.h"
17#include "llvm/IR/IRBuilder.h"
18#include "llvm/IR/Instructions.h"
19#include "llvm/IR/Intrinsics.h"
20#include "llvm/IR/Module.h"
21#include "llvm/Pass.h"
22
23using namespace llvm;
24
25namespace {
26
27bool lowerLoadRelative(Function &F) {
28  if (F.use_empty())
29    return false;
30
31  bool Changed = false;
32  Type *Int32Ty = Type::getInt32Ty(F.getContext());
33  Type *Int32PtrTy = Int32Ty->getPointerTo();
34  Type *Int8Ty = Type::getInt8Ty(F.getContext());
35
36  for (auto I = F.use_begin(), E = F.use_end(); I != E;) {
37    auto CI = dyn_cast<CallInst>(I->getUser());
38    ++I;
39    if (!CI || CI->getCalledValue() != &F)
40      continue;
41
42    IRBuilder<> B(CI);
43    Value *OffsetPtr =
44        B.CreateGEP(Int8Ty, CI->getArgOperand(0), CI->getArgOperand(1));
45    Value *OffsetPtrI32 = B.CreateBitCast(OffsetPtr, Int32PtrTy);
46    Value *OffsetI32 = B.CreateAlignedLoad(OffsetPtrI32, 4);
47
48    Value *ResultPtr = B.CreateGEP(Int8Ty, CI->getArgOperand(0), OffsetI32);
49
50    CI->replaceAllUsesWith(ResultPtr);
51    CI->eraseFromParent();
52    Changed = true;
53  }
54
55  return Changed;
56}
57
58bool lowerIntrinsics(Module &M) {
59  bool Changed = false;
60  for (Function &F : M) {
61    if (F.getName().startswith("llvm.load.relative."))
62      Changed |= lowerLoadRelative(F);
63  }
64  return Changed;
65}
66
67class PreISelIntrinsicLoweringLegacyPass : public ModulePass {
68public:
69  static char ID;
70  PreISelIntrinsicLoweringLegacyPass() : ModulePass(ID) {}
71
72  bool runOnModule(Module &M) { return lowerIntrinsics(M); }
73};
74
75char PreISelIntrinsicLoweringLegacyPass::ID;
76}
77
78INITIALIZE_PASS(PreISelIntrinsicLoweringLegacyPass,
79                "pre-isel-intrinsic-lowering", "Pre-ISel Intrinsic Lowering",
80                false, false)
81
82namespace llvm {
83ModulePass *createPreISelIntrinsicLoweringPass() {
84  return new PreISelIntrinsicLoweringLegacyPass;
85}
86
87PreservedAnalyses PreISelIntrinsicLoweringPass::run(Module &M,
88                                                    ModuleAnalysisManager &AM) {
89  if (!lowerIntrinsics(M))
90    return PreservedAnalyses::all();
91  else
92    return PreservedAnalyses::none();
93}
94} // End llvm namespace
95