blob: 973ffe7e6a40f4a03dc15ac2cbadda2f93b614f0 [file] [log] [blame]
Peter Collingbourne3bababf2010-08-03 16:19:16 +00001//===- 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/BasicBlock.h"
18#include "llvm/Function.h"
19#include "llvm/Instruction.h"
20#include "llvm/Instructions.h"
21#include "llvm/Intrinsics.h"
22#include "llvm/Pass.h"
23#include "llvm/Support/IRBuilder.h"
24
25using namespace llvm;
26
27namespace {
28
29bool LowerAtomicIntrinsic(CallInst *CI) {
30 IRBuilder<> Builder(CI->getParent(), CI);
31
32 Function *Callee = CI->getCalledFunction();
33 if (!Callee)
34 return false;
35
36 unsigned IID = Callee->getIntrinsicID();
37 switch (IID) {
38 case Intrinsic::memory_barrier:
39 break;
40
41 case Intrinsic::atomic_load_add:
42 case Intrinsic::atomic_load_sub:
43 case Intrinsic::atomic_load_and:
44 case Intrinsic::atomic_load_nand:
45 case Intrinsic::atomic_load_or:
46 case Intrinsic::atomic_load_xor:
47 case Intrinsic::atomic_load_max:
48 case Intrinsic::atomic_load_min:
49 case Intrinsic::atomic_load_umax:
50 case Intrinsic::atomic_load_umin: {
51 Value *Ptr = CI->getArgOperand(0);
52 Value *Delta = CI->getArgOperand(1);
53
54 LoadInst *Orig = Builder.CreateLoad(Ptr);
Nick Lewyckye52e9d62010-08-06 07:43:46 +000055 Value *Res = NULL;
Peter Collingbourne3bababf2010-08-03 16:19:16 +000056 switch (IID) {
Nick Lewyckye52e9d62010-08-06 07:43:46 +000057 default: assert(0 && "Unrecognized atomic modify operation");
Peter Collingbourne3bababf2010-08-03 16:19:16 +000058 case Intrinsic::atomic_load_add:
59 Res = Builder.CreateAdd(Orig, Delta);
60 break;
61 case Intrinsic::atomic_load_sub:
62 Res = Builder.CreateSub(Orig, Delta);
63 break;
64 case Intrinsic::atomic_load_and:
65 Res = Builder.CreateAnd(Orig, Delta);
66 break;
67 case Intrinsic::atomic_load_nand:
68 Res = Builder.CreateNot(Builder.CreateAnd(Orig, Delta));
69 break;
70 case Intrinsic::atomic_load_or:
71 Res = Builder.CreateOr(Orig, Delta);
72 break;
73 case Intrinsic::atomic_load_xor:
74 Res = Builder.CreateXor(Orig, Delta);
75 break;
76 case Intrinsic::atomic_load_max:
77 Res = Builder.CreateSelect(Builder.CreateICmpSLT(Orig, Delta),
78 Delta,
79 Orig);
80 break;
81 case Intrinsic::atomic_load_min:
82 Res = Builder.CreateSelect(Builder.CreateICmpSLT(Orig, Delta),
83 Orig,
84 Delta);
85 break;
86 case Intrinsic::atomic_load_umax:
87 Res = Builder.CreateSelect(Builder.CreateICmpULT(Orig, Delta),
88 Delta,
89 Orig);
90 break;
91 case Intrinsic::atomic_load_umin:
92 Res = Builder.CreateSelect(Builder.CreateICmpULT(Orig, Delta),
93 Orig,
94 Delta);
95 break;
Peter Collingbourne3bababf2010-08-03 16:19:16 +000096 }
97 Builder.CreateStore(Res, Ptr);
98
99 CI->replaceAllUsesWith(Orig);
100 break;
101 }
102
103 case Intrinsic::atomic_swap: {
104 Value *Ptr = CI->getArgOperand(0);
105 Value *Val = CI->getArgOperand(1);
106
107 LoadInst *Orig = Builder.CreateLoad(Ptr);
108 Builder.CreateStore(Val, Ptr);
109
110 CI->replaceAllUsesWith(Orig);
111 break;
112 }
113
114 case Intrinsic::atomic_cmp_swap: {
115 Value *Ptr = CI->getArgOperand(0);
116 Value *Cmp = CI->getArgOperand(1);
117 Value *Val = CI->getArgOperand(2);
118
119 LoadInst *Orig = Builder.CreateLoad(Ptr);
120 Value *Equal = Builder.CreateICmpEQ(Orig, Cmp);
121 Value *Res = Builder.CreateSelect(Equal, Val, Orig);
122 Builder.CreateStore(Res, Ptr);
123
124 CI->replaceAllUsesWith(Orig);
125 break;
126 }
127
128 default:
129 return false;
130 }
131
132 assert(CI->use_empty() &&
133 "Lowering should have eliminated any uses of the intrinsic call!");
134 CI->eraseFromParent();
135
136 return true;
137}
138
139struct LowerAtomic : public BasicBlockPass {
140 static char ID;
Owen Anderson90c579d2010-08-06 18:33:48 +0000141 LowerAtomic() : BasicBlockPass(ID) {}
Peter Collingbourne3bababf2010-08-03 16:19:16 +0000142 bool runOnBasicBlock(BasicBlock &BB) {
143 bool Changed = false;
144 for (BasicBlock::iterator DI = BB.begin(), DE = BB.end(); DI != DE; ) {
145 Instruction *Inst = DI++;
146 if (CallInst *CI = dyn_cast<CallInst>(Inst))
147 Changed |= LowerAtomicIntrinsic(CI);
148 }
149 return Changed;
150 }
151
152};
153
154}
155
156char LowerAtomic::ID = 0;
Owen Anderson02dd53e2010-08-23 17:52:01 +0000157INITIALIZE_PASS(LowerAtomic, "loweratomic",
158 "Lower atomic intrinsics to non-atomic form",
159 false, false);
Peter Collingbourne3bababf2010-08-03 16:19:16 +0000160
161Pass *llvm::createLowerAtomicPass() { return new LowerAtomic(); }