LowerAtomic.cpp revision 212904
1252190Srpaulo//===- LowerAtomic.cpp - Lower atomic intrinsics --------------------------===//
2252190Srpaulo//
3252190Srpaulo//                     The LLVM Compiler Infrastructure
4252190Srpaulo//
5252190Srpaulo// This file is distributed under the University of Illinois Open Source
6252190Srpaulo// License. See LICENSE.TXT for details.
7252190Srpaulo//
8252190Srpaulo//===----------------------------------------------------------------------===//
9252190Srpaulo//
10252190Srpaulo// This pass lowers atomic intrinsics to non-atomic form for use in a known
11252190Srpaulo// non-preemptible environment.
12252190Srpaulo//
13252190Srpaulo//===----------------------------------------------------------------------===//
14252190Srpaulo
15252190Srpaulo#define DEBUG_TYPE "loweratomic"
16252190Srpaulo#include "llvm/Transforms/Scalar.h"
17252190Srpaulo#include "llvm/BasicBlock.h"
18252190Srpaulo#include "llvm/Function.h"
19252190Srpaulo#include "llvm/Instruction.h"
20252190Srpaulo#include "llvm/Instructions.h"
21252190Srpaulo#include "llvm/Intrinsics.h"
22252190Srpaulo#include "llvm/Pass.h"
23252190Srpaulo#include "llvm/Support/IRBuilder.h"
24252190Srpaulo
25252190Srpaulousing namespace llvm;
26252190Srpaulo
27252190Srpaulonamespace {
28252190Srpaulo
29252190Srpaulobool LowerAtomicIntrinsic(CallInst *CI) {
30252190Srpaulo  IRBuilder<> Builder(CI->getParent(), CI);
31252190Srpaulo
32252190Srpaulo  Function *Callee = CI->getCalledFunction();
33252190Srpaulo  if (!Callee)
34252190Srpaulo    return false;
35252190Srpaulo
36252190Srpaulo  unsigned IID = Callee->getIntrinsicID();
37252190Srpaulo  switch (IID) {
38252190Srpaulo  case Intrinsic::memory_barrier:
39252190Srpaulo    break;
40252190Srpaulo
41252190Srpaulo  case Intrinsic::atomic_load_add:
42252190Srpaulo  case Intrinsic::atomic_load_sub:
43252190Srpaulo  case Intrinsic::atomic_load_and:
44252190Srpaulo  case Intrinsic::atomic_load_nand:
45252190Srpaulo  case Intrinsic::atomic_load_or:
46252190Srpaulo  case Intrinsic::atomic_load_xor:
47252190Srpaulo  case Intrinsic::atomic_load_max:
48252190Srpaulo  case Intrinsic::atomic_load_min:
49252190Srpaulo  case Intrinsic::atomic_load_umax:
50252190Srpaulo  case Intrinsic::atomic_load_umin: {
51252190Srpaulo    Value *Ptr = CI->getArgOperand(0);
52252190Srpaulo    Value *Delta = CI->getArgOperand(1);
53252190Srpaulo
54252190Srpaulo    LoadInst *Orig = Builder.CreateLoad(Ptr);
55252190Srpaulo    Value *Res = NULL;
56252190Srpaulo    switch (IID) {
57252190Srpaulo      default: assert(0 && "Unrecognized atomic modify operation");
58252190Srpaulo      case Intrinsic::atomic_load_add:
59252190Srpaulo        Res = Builder.CreateAdd(Orig, Delta);
60252190Srpaulo        break;
61252190Srpaulo      case Intrinsic::atomic_load_sub:
62252190Srpaulo        Res = Builder.CreateSub(Orig, Delta);
63252190Srpaulo        break;
64252190Srpaulo      case Intrinsic::atomic_load_and:
65252190Srpaulo        Res = Builder.CreateAnd(Orig, Delta);
66252190Srpaulo        break;
67252190Srpaulo      case Intrinsic::atomic_load_nand:
68252190Srpaulo        Res = Builder.CreateNot(Builder.CreateAnd(Orig, Delta));
69252190Srpaulo        break;
70252190Srpaulo      case Intrinsic::atomic_load_or:
71252190Srpaulo        Res = Builder.CreateOr(Orig, Delta);
72281806Srpaulo        break;
73281806Srpaulo      case Intrinsic::atomic_load_xor:
74281806Srpaulo        Res = Builder.CreateXor(Orig, Delta);
75281806Srpaulo        break;
76281806Srpaulo      case Intrinsic::atomic_load_max:
77281806Srpaulo        Res = Builder.CreateSelect(Builder.CreateICmpSLT(Orig, Delta),
78281806Srpaulo                                   Delta,
79281806Srpaulo                                   Orig);
80281806Srpaulo        break;
81281806Srpaulo      case Intrinsic::atomic_load_min:
82281806Srpaulo        Res = Builder.CreateSelect(Builder.CreateICmpSLT(Orig, Delta),
83252190Srpaulo                                   Orig,
84252190Srpaulo                                   Delta);
85252190Srpaulo        break;
86252190Srpaulo      case Intrinsic::atomic_load_umax:
87252190Srpaulo        Res = Builder.CreateSelect(Builder.CreateICmpULT(Orig, Delta),
88281806Srpaulo                                   Delta,
89281806Srpaulo                                   Orig);
90281806Srpaulo        break;
91281806Srpaulo      case Intrinsic::atomic_load_umin:
92281806Srpaulo        Res = Builder.CreateSelect(Builder.CreateICmpULT(Orig, Delta),
93281806Srpaulo                                   Orig,
94281806Srpaulo                                   Delta);
95281806Srpaulo        break;
96281806Srpaulo    }
97281806Srpaulo    Builder.CreateStore(Res, Ptr);
98281806Srpaulo
99281806Srpaulo    CI->replaceAllUsesWith(Orig);
100281806Srpaulo    break;
101281806Srpaulo  }
102281806Srpaulo
103281806Srpaulo  case Intrinsic::atomic_swap: {
104281806Srpaulo    Value *Ptr = CI->getArgOperand(0);
105281806Srpaulo    Value *Val = CI->getArgOperand(1);
106281806Srpaulo
107281806Srpaulo    LoadInst *Orig = Builder.CreateLoad(Ptr);
108281806Srpaulo    Builder.CreateStore(Val, Ptr);
109281806Srpaulo
110281806Srpaulo    CI->replaceAllUsesWith(Orig);
111281806Srpaulo    break;
112281806Srpaulo  }
113281806Srpaulo
114281806Srpaulo  case Intrinsic::atomic_cmp_swap: {
115281806Srpaulo    Value *Ptr = CI->getArgOperand(0);
116281806Srpaulo    Value *Cmp = CI->getArgOperand(1);
117281806Srpaulo    Value *Val = CI->getArgOperand(2);
118281806Srpaulo
119281806Srpaulo    LoadInst *Orig = Builder.CreateLoad(Ptr);
120281806Srpaulo    Value *Equal = Builder.CreateICmpEQ(Orig, Cmp);
121281806Srpaulo    Value *Res = Builder.CreateSelect(Equal, Val, Orig);
122281806Srpaulo    Builder.CreateStore(Res, Ptr);
123281806Srpaulo
124281806Srpaulo    CI->replaceAllUsesWith(Orig);
125281806Srpaulo    break;
126281806Srpaulo  }
127281806Srpaulo
128281806Srpaulo  default:
129281806Srpaulo    return false;
130281806Srpaulo  }
131281806Srpaulo
132281806Srpaulo  assert(CI->use_empty() &&
133281806Srpaulo         "Lowering should have eliminated any uses of the intrinsic call!");
134281806Srpaulo  CI->eraseFromParent();
135281806Srpaulo
136281806Srpaulo  return true;
137281806Srpaulo}
138281806Srpaulo
139281806Srpaulostruct LowerAtomic : public BasicBlockPass {
140281806Srpaulo  static char ID;
141281806Srpaulo  LowerAtomic() : BasicBlockPass(ID) {}
142281806Srpaulo  bool runOnBasicBlock(BasicBlock &BB) {
143281806Srpaulo    bool Changed = false;
144281806Srpaulo    for (BasicBlock::iterator DI = BB.begin(), DE = BB.end(); DI != DE; ) {
145281806Srpaulo      Instruction *Inst = DI++;
146281806Srpaulo      if (CallInst *CI = dyn_cast<CallInst>(Inst))
147281806Srpaulo        Changed |= LowerAtomicIntrinsic(CI);
148281806Srpaulo    }
149281806Srpaulo    return Changed;
150281806Srpaulo  }
151281806Srpaulo
152281806Srpaulo};
153281806Srpaulo
154281806Srpaulo}
155281806Srpaulo
156281806Srpaulochar LowerAtomic::ID = 0;
157281806SrpauloINITIALIZE_PASS(LowerAtomic, "loweratomic",
158281806Srpaulo                "Lower atomic intrinsics to non-atomic form",
159281806Srpaulo                false, false);
160281806Srpaulo
161281806SrpauloPass *llvm::createLowerAtomicPass() { return new LowerAtomic(); }
162281806Srpaulo