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/IntrinsicInst.h"
22 #include "llvm/Intrinsics.h"
23 #include "llvm/Pass.h"
24 #include "llvm/Support/IRBuilder.h"
27 static bool LowerAtomicIntrinsic(IntrinsicInst *II) {
28 IRBuilder<> Builder(II->getParent(), II);
29 unsigned IID = II->getIntrinsicID();
31 case Intrinsic::memory_barrier:
34 case Intrinsic::atomic_load_add:
35 case Intrinsic::atomic_load_sub:
36 case Intrinsic::atomic_load_and:
37 case Intrinsic::atomic_load_nand:
38 case Intrinsic::atomic_load_or:
39 case Intrinsic::atomic_load_xor:
40 case Intrinsic::atomic_load_max:
41 case Intrinsic::atomic_load_min:
42 case Intrinsic::atomic_load_umax:
43 case Intrinsic::atomic_load_umin: {
44 Value *Ptr = II->getArgOperand(0);
45 Value *Delta = II->getArgOperand(1);
47 LoadInst *Orig = Builder.CreateLoad(Ptr);
50 default: assert(0 && "Unrecognized atomic modify operation");
51 case Intrinsic::atomic_load_add:
52 Res = Builder.CreateAdd(Orig, Delta);
54 case Intrinsic::atomic_load_sub:
55 Res = Builder.CreateSub(Orig, Delta);
57 case Intrinsic::atomic_load_and:
58 Res = Builder.CreateAnd(Orig, Delta);
60 case Intrinsic::atomic_load_nand:
61 Res = Builder.CreateNot(Builder.CreateAnd(Orig, Delta));
63 case Intrinsic::atomic_load_or:
64 Res = Builder.CreateOr(Orig, Delta);
66 case Intrinsic::atomic_load_xor:
67 Res = Builder.CreateXor(Orig, Delta);
69 case Intrinsic::atomic_load_max:
70 Res = Builder.CreateSelect(Builder.CreateICmpSLT(Orig, Delta),
74 case Intrinsic::atomic_load_min:
75 Res = Builder.CreateSelect(Builder.CreateICmpSLT(Orig, Delta),
79 case Intrinsic::atomic_load_umax:
80 Res = Builder.CreateSelect(Builder.CreateICmpULT(Orig, Delta),
84 case Intrinsic::atomic_load_umin:
85 Res = Builder.CreateSelect(Builder.CreateICmpULT(Orig, Delta),
90 Builder.CreateStore(Res, Ptr);
92 II->replaceAllUsesWith(Orig);
96 case Intrinsic::atomic_swap: {
97 Value *Ptr = II->getArgOperand(0);
98 Value *Val = II->getArgOperand(1);
100 LoadInst *Orig = Builder.CreateLoad(Ptr);
101 Builder.CreateStore(Val, Ptr);
103 II->replaceAllUsesWith(Orig);
107 case Intrinsic::atomic_cmp_swap: {
108 Value *Ptr = II->getArgOperand(0);
109 Value *Cmp = II->getArgOperand(1);
110 Value *Val = II->getArgOperand(2);
112 LoadInst *Orig = Builder.CreateLoad(Ptr);
113 Value *Equal = Builder.CreateICmpEQ(Orig, Cmp);
114 Value *Res = Builder.CreateSelect(Equal, Val, Orig);
115 Builder.CreateStore(Res, Ptr);
117 II->replaceAllUsesWith(Orig);
125 assert(II->use_empty() &&
126 "Lowering should have eliminated any uses of the intrinsic call!");
127 II->eraseFromParent();
133 struct LowerAtomic : public BasicBlockPass {
135 LowerAtomic() : BasicBlockPass(ID) {}
136 bool runOnBasicBlock(BasicBlock &BB) {
137 bool Changed = false;
138 for (BasicBlock::iterator DI = BB.begin(), DE = BB.end(); DI != DE; )
139 if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(DI++))
140 Changed |= LowerAtomicIntrinsic(II);
146 char LowerAtomic::ID = 0;
147 INITIALIZE_PASS(LowerAtomic, "loweratomic",
148 "Lower atomic intrinsics to non-atomic form",
151 Pass *llvm::createLowerAtomicPass() { return new LowerAtomic(); }