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 default: assert(0 && "Unrecognized atomic modify operation");
58 case Intrinsic::atomic_load_add:
59 Res = Builder.CreateAdd(Orig, Delta);
61 case Intrinsic::atomic_load_sub:
62 Res = Builder.CreateSub(Orig, Delta);
64 case Intrinsic::atomic_load_and:
65 Res = Builder.CreateAnd(Orig, Delta);
67 case Intrinsic::atomic_load_nand:
68 Res = Builder.CreateNot(Builder.CreateAnd(Orig, Delta));
70 case Intrinsic::atomic_load_or:
71 Res = Builder.CreateOr(Orig, Delta);
73 case Intrinsic::atomic_load_xor:
74 Res = Builder.CreateXor(Orig, Delta);
76 case Intrinsic::atomic_load_max:
77 Res = Builder.CreateSelect(Builder.CreateICmpSLT(Orig, Delta),
81 case Intrinsic::atomic_load_min:
82 Res = Builder.CreateSelect(Builder.CreateICmpSLT(Orig, Delta),
86 case Intrinsic::atomic_load_umax:
87 Res = Builder.CreateSelect(Builder.CreateICmpULT(Orig, Delta),
91 case Intrinsic::atomic_load_umin:
92 Res = Builder.CreateSelect(Builder.CreateICmpULT(Orig, Delta),
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(); }