1 //===- LowerAtomic.cpp - Lower atomic intrinsics --------------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This pass lowers atomic intrinsics to non-atomic form for use in a known
11 // non-preemptible environment.
13 //===----------------------------------------------------------------------===//
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"
29 bool LowerAtomicIntrinsic(CallInst *CI) {
30 IRBuilder<> Builder(CI->getParent(), CI);
32 Function *Callee = CI->getCalledFunction();
36 unsigned IID = Callee->getIntrinsicID();
38 case Intrinsic::memory_barrier:
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);
54 LoadInst *Orig = Builder.CreateLoad(Ptr);
57 case Intrinsic::atomic_load_add:
58 Res = Builder.CreateAdd(Orig, Delta);
60 case Intrinsic::atomic_load_sub:
61 Res = Builder.CreateSub(Orig, Delta);
63 case Intrinsic::atomic_load_and:
64 Res = Builder.CreateAnd(Orig, Delta);
66 case Intrinsic::atomic_load_nand:
67 Res = Builder.CreateNot(Builder.CreateAnd(Orig, Delta));
69 case Intrinsic::atomic_load_or:
70 Res = Builder.CreateOr(Orig, Delta);
72 case Intrinsic::atomic_load_xor:
73 Res = Builder.CreateXor(Orig, Delta);
75 case Intrinsic::atomic_load_max:
76 Res = Builder.CreateSelect(Builder.CreateICmpSLT(Orig, Delta),
80 case Intrinsic::atomic_load_min:
81 Res = Builder.CreateSelect(Builder.CreateICmpSLT(Orig, Delta),
85 case Intrinsic::atomic_load_umax:
86 Res = Builder.CreateSelect(Builder.CreateICmpULT(Orig, Delta),
90 case Intrinsic::atomic_load_umin:
91 Res = Builder.CreateSelect(Builder.CreateICmpULT(Orig, Delta),
95 default: assert(0 && "Unrecognized atomic modify operation");
97 Builder.CreateStore(Res, Ptr);
99 CI->replaceAllUsesWith(Orig);
103 case Intrinsic::atomic_swap: {
104 Value *Ptr = CI->getArgOperand(0);
105 Value *Val = CI->getArgOperand(1);
107 LoadInst *Orig = Builder.CreateLoad(Ptr);
108 Builder.CreateStore(Val, Ptr);
110 CI->replaceAllUsesWith(Orig);
114 case Intrinsic::atomic_cmp_swap: {
115 Value *Ptr = CI->getArgOperand(0);
116 Value *Cmp = CI->getArgOperand(1);
117 Value *Val = CI->getArgOperand(2);
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);
124 CI->replaceAllUsesWith(Orig);
132 assert(CI->use_empty() &&
133 "Lowering should have eliminated any uses of the intrinsic call!");
134 CI->eraseFromParent();
139 struct LowerAtomic : public BasicBlockPass {
141 LowerAtomic() : BasicBlockPass(&ID) {}
142 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);
156 char LowerAtomic::ID = 0;
157 static RegisterPass<LowerAtomic>
158 X("loweratomic", "Lower atomic intrinsics to non-atomic form");
160 Pass *llvm::createLowerAtomicPass() { return new LowerAtomic(); }