LowerAtomic.cpp revision 218893
1//===- LowerAtomic.cpp - Lower atomic intrinsics --------------------------===//
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 lowers atomic intrinsics to non-atomic form for use in a known
11// non-preemptible environment.
12//
13//===----------------------------------------------------------------------===//
14
15#define DEBUG_TYPE "loweratomic"
16#include "llvm/Transforms/Scalar.h"
17#include "llvm/Function.h"
18#include "llvm/IntrinsicInst.h"
19#include "llvm/Pass.h"
20#include "llvm/Support/IRBuilder.h"
21using namespace llvm;
22
23static bool LowerAtomicIntrinsic(IntrinsicInst *II) {
24  IRBuilder<> Builder(II->getParent(), II);
25  unsigned IID = II->getIntrinsicID();
26  switch (IID) {
27  case Intrinsic::memory_barrier:
28    break;
29
30  case Intrinsic::atomic_load_add:
31  case Intrinsic::atomic_load_sub:
32  case Intrinsic::atomic_load_and:
33  case Intrinsic::atomic_load_nand:
34  case Intrinsic::atomic_load_or:
35  case Intrinsic::atomic_load_xor:
36  case Intrinsic::atomic_load_max:
37  case Intrinsic::atomic_load_min:
38  case Intrinsic::atomic_load_umax:
39  case Intrinsic::atomic_load_umin: {
40    Value *Ptr = II->getArgOperand(0), *Delta = II->getArgOperand(1);
41
42    LoadInst *Orig = Builder.CreateLoad(Ptr);
43    Value *Res = NULL;
44    switch (IID) {
45    default: assert(0 && "Unrecognized atomic modify operation");
46    case Intrinsic::atomic_load_add:
47      Res = Builder.CreateAdd(Orig, Delta);
48      break;
49    case Intrinsic::atomic_load_sub:
50      Res = Builder.CreateSub(Orig, Delta);
51      break;
52    case Intrinsic::atomic_load_and:
53      Res = Builder.CreateAnd(Orig, Delta);
54      break;
55    case Intrinsic::atomic_load_nand:
56      Res = Builder.CreateNot(Builder.CreateAnd(Orig, Delta));
57      break;
58    case Intrinsic::atomic_load_or:
59      Res = Builder.CreateOr(Orig, Delta);
60      break;
61    case Intrinsic::atomic_load_xor:
62      Res = Builder.CreateXor(Orig, Delta);
63      break;
64    case Intrinsic::atomic_load_max:
65      Res = Builder.CreateSelect(Builder.CreateICmpSLT(Orig, Delta),
66                                 Delta, Orig);
67      break;
68    case Intrinsic::atomic_load_min:
69      Res = Builder.CreateSelect(Builder.CreateICmpSLT(Orig, Delta),
70                                 Orig, Delta);
71      break;
72    case Intrinsic::atomic_load_umax:
73      Res = Builder.CreateSelect(Builder.CreateICmpULT(Orig, Delta),
74                                 Delta, Orig);
75      break;
76    case Intrinsic::atomic_load_umin:
77      Res = Builder.CreateSelect(Builder.CreateICmpULT(Orig, Delta),
78                                 Orig, Delta);
79      break;
80    }
81    Builder.CreateStore(Res, Ptr);
82
83    II->replaceAllUsesWith(Orig);
84    break;
85  }
86
87  case Intrinsic::atomic_swap: {
88    Value *Ptr = II->getArgOperand(0), *Val = II->getArgOperand(1);
89    LoadInst *Orig = Builder.CreateLoad(Ptr);
90    Builder.CreateStore(Val, Ptr);
91    II->replaceAllUsesWith(Orig);
92    break;
93  }
94
95  case Intrinsic::atomic_cmp_swap: {
96    Value *Ptr = II->getArgOperand(0), *Cmp = II->getArgOperand(1);
97    Value *Val = II->getArgOperand(2);
98
99    LoadInst *Orig = Builder.CreateLoad(Ptr);
100    Value *Equal = Builder.CreateICmpEQ(Orig, Cmp);
101    Value *Res = Builder.CreateSelect(Equal, Val, Orig);
102    Builder.CreateStore(Res, Ptr);
103    II->replaceAllUsesWith(Orig);
104    break;
105  }
106
107  default:
108    return false;
109  }
110
111  assert(II->use_empty() &&
112         "Lowering should have eliminated any uses of the intrinsic call!");
113  II->eraseFromParent();
114
115  return true;
116}
117
118namespace {
119  struct LowerAtomic : public BasicBlockPass {
120    static char ID;
121    LowerAtomic() : BasicBlockPass(ID) {
122      initializeLowerAtomicPass(*PassRegistry::getPassRegistry());
123    }
124    bool runOnBasicBlock(BasicBlock &BB) {
125      bool Changed = false;
126      for (BasicBlock::iterator DI = BB.begin(), DE = BB.end(); DI != DE; )
127        if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(DI++))
128          Changed |= LowerAtomicIntrinsic(II);
129      return Changed;
130    }
131  };
132}
133
134char LowerAtomic::ID = 0;
135INITIALIZE_PASS(LowerAtomic, "loweratomic",
136                "Lower atomic intrinsics to non-atomic form",
137                false, false)
138
139Pass *llvm::createLowerAtomicPass() { return new LowerAtomic(); }
140