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/Function.h"
18 #include "llvm/IntrinsicInst.h"
19 #include "llvm/Pass.h"
20 #include "llvm/Support/IRBuilder.h"
23 static bool LowerAtomicIntrinsic(IntrinsicInst
*II
) {
24 IRBuilder
<> Builder(II
->getParent(), II
);
25 unsigned IID
= II
->getIntrinsicID();
27 case Intrinsic::memory_barrier
:
30 case Intrinsic::atomic_load_add
:
31 case Intrinsic::atomic_load_sub
:
32 case Intrinsic::atomic_load_and
:
33 case Intrinsic::atomic_load_nand
:
34 case Intrinsic::atomic_load_or
:
35 case Intrinsic::atomic_load_xor
:
36 case Intrinsic::atomic_load_max
:
37 case Intrinsic::atomic_load_min
:
38 case Intrinsic::atomic_load_umax
:
39 case Intrinsic::atomic_load_umin
: {
40 Value
*Ptr
= II
->getArgOperand(0), *Delta
= II
->getArgOperand(1);
42 LoadInst
*Orig
= Builder
.CreateLoad(Ptr
);
45 default: assert(0 && "Unrecognized atomic modify operation");
46 case Intrinsic::atomic_load_add
:
47 Res
= Builder
.CreateAdd(Orig
, Delta
);
49 case Intrinsic::atomic_load_sub
:
50 Res
= Builder
.CreateSub(Orig
, Delta
);
52 case Intrinsic::atomic_load_and
:
53 Res
= Builder
.CreateAnd(Orig
, Delta
);
55 case Intrinsic::atomic_load_nand
:
56 Res
= Builder
.CreateNot(Builder
.CreateAnd(Orig
, Delta
));
58 case Intrinsic::atomic_load_or
:
59 Res
= Builder
.CreateOr(Orig
, Delta
);
61 case Intrinsic::atomic_load_xor
:
62 Res
= Builder
.CreateXor(Orig
, Delta
);
64 case Intrinsic::atomic_load_max
:
65 Res
= Builder
.CreateSelect(Builder
.CreateICmpSLT(Orig
, Delta
),
68 case Intrinsic::atomic_load_min
:
69 Res
= Builder
.CreateSelect(Builder
.CreateICmpSLT(Orig
, Delta
),
72 case Intrinsic::atomic_load_umax
:
73 Res
= Builder
.CreateSelect(Builder
.CreateICmpULT(Orig
, Delta
),
76 case Intrinsic::atomic_load_umin
:
77 Res
= Builder
.CreateSelect(Builder
.CreateICmpULT(Orig
, Delta
),
81 Builder
.CreateStore(Res
, Ptr
);
83 II
->replaceAllUsesWith(Orig
);
87 case Intrinsic::atomic_swap
: {
88 Value
*Ptr
= II
->getArgOperand(0), *Val
= II
->getArgOperand(1);
89 LoadInst
*Orig
= Builder
.CreateLoad(Ptr
);
90 Builder
.CreateStore(Val
, Ptr
);
91 II
->replaceAllUsesWith(Orig
);
95 case Intrinsic::atomic_cmp_swap
: {
96 Value
*Ptr
= II
->getArgOperand(0), *Cmp
= II
->getArgOperand(1);
97 Value
*Val
= II
->getArgOperand(2);
99 LoadInst
*Orig
= Builder
.CreateLoad(Ptr
);
100 Value
*Equal
= Builder
.CreateICmpEQ(Orig
, Cmp
);
101 Value
*Res
= Builder
.CreateSelect(Equal
, Val
, Orig
);
102 Builder
.CreateStore(Res
, Ptr
);
103 II
->replaceAllUsesWith(Orig
);
111 assert(II
->use_empty() &&
112 "Lowering should have eliminated any uses of the intrinsic call!");
113 II
->eraseFromParent();
119 struct LowerAtomic
: public BasicBlockPass
{
121 LowerAtomic() : BasicBlockPass(ID
) {
122 initializeLowerAtomicPass(*PassRegistry::getPassRegistry());
124 bool runOnBasicBlock(BasicBlock
&BB
) {
125 bool Changed
= false;
126 for (BasicBlock::iterator DI
= BB
.begin(), DE
= BB
.end(); DI
!= DE
; )
127 if (IntrinsicInst
*II
= dyn_cast
<IntrinsicInst
>(DI
++))
128 Changed
|= LowerAtomicIntrinsic(II
);
134 char LowerAtomic::ID
= 0;
135 INITIALIZE_PASS(LowerAtomic
, "loweratomic",
136 "Lower atomic intrinsics to non-atomic form",
139 Pass
*llvm::createLowerAtomicPass() { return new LowerAtomic(); }