blob: db2dc46da9296d86116f30f3b48f9b853e7d28b8 [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"
Chris Lattnerbdabacd2010-09-05 20:10:47 +000021#include "llvm/IntrinsicInst.h"
Peter Collingbourne3bababf2010-08-03 16:19:16 +000022#include "llvm/Intrinsics.h"
23#include "llvm/Pass.h"
24#include "llvm/Support/IRBuilder.h"
Peter Collingbourne3bababf2010-08-03 16:19:16 +000025using namespace llvm;
26
Chris Lattnerbdabacd2010-09-05 20:10:47 +000027static bool LowerAtomicIntrinsic(IntrinsicInst *II) {
28 IRBuilder<> Builder(II->getParent(), II);
29 unsigned IID = II->getIntrinsicID();
Peter Collingbourne3bababf2010-08-03 16:19:16 +000030 switch (IID) {
31 case Intrinsic::memory_barrier:
32 break;
33
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: {
Chris Lattnerbdabacd2010-09-05 20:10:47 +000044 Value *Ptr = II->getArgOperand(0);
45 Value *Delta = II->getArgOperand(1);
Peter Collingbourne3bababf2010-08-03 16:19:16 +000046
47 LoadInst *Orig = Builder.CreateLoad(Ptr);
Nick Lewyckye52e9d62010-08-06 07:43:46 +000048 Value *Res = NULL;
Peter Collingbourne3bababf2010-08-03 16:19:16 +000049 switch (IID) {
Nick Lewyckye52e9d62010-08-06 07:43:46 +000050 default: assert(0 && "Unrecognized atomic modify operation");
Peter Collingbourne3bababf2010-08-03 16:19:16 +000051 case Intrinsic::atomic_load_add:
52 Res = Builder.CreateAdd(Orig, Delta);
53 break;
54 case Intrinsic::atomic_load_sub:
55 Res = Builder.CreateSub(Orig, Delta);
56 break;
57 case Intrinsic::atomic_load_and:
58 Res = Builder.CreateAnd(Orig, Delta);
59 break;
60 case Intrinsic::atomic_load_nand:
61 Res = Builder.CreateNot(Builder.CreateAnd(Orig, Delta));
62 break;
63 case Intrinsic::atomic_load_or:
64 Res = Builder.CreateOr(Orig, Delta);
65 break;
66 case Intrinsic::atomic_load_xor:
67 Res = Builder.CreateXor(Orig, Delta);
68 break;
69 case Intrinsic::atomic_load_max:
70 Res = Builder.CreateSelect(Builder.CreateICmpSLT(Orig, Delta),
71 Delta,
72 Orig);
73 break;
74 case Intrinsic::atomic_load_min:
75 Res = Builder.CreateSelect(Builder.CreateICmpSLT(Orig, Delta),
76 Orig,
77 Delta);
78 break;
79 case Intrinsic::atomic_load_umax:
80 Res = Builder.CreateSelect(Builder.CreateICmpULT(Orig, Delta),
81 Delta,
82 Orig);
83 break;
84 case Intrinsic::atomic_load_umin:
85 Res = Builder.CreateSelect(Builder.CreateICmpULT(Orig, Delta),
86 Orig,
87 Delta);
88 break;
Peter Collingbourne3bababf2010-08-03 16:19:16 +000089 }
90 Builder.CreateStore(Res, Ptr);
91
Chris Lattnerbdabacd2010-09-05 20:10:47 +000092 II->replaceAllUsesWith(Orig);
Peter Collingbourne3bababf2010-08-03 16:19:16 +000093 break;
94 }
95
96 case Intrinsic::atomic_swap: {
Chris Lattnerbdabacd2010-09-05 20:10:47 +000097 Value *Ptr = II->getArgOperand(0);
98 Value *Val = II->getArgOperand(1);
Peter Collingbourne3bababf2010-08-03 16:19:16 +000099
100 LoadInst *Orig = Builder.CreateLoad(Ptr);
101 Builder.CreateStore(Val, Ptr);
102
Chris Lattnerbdabacd2010-09-05 20:10:47 +0000103 II->replaceAllUsesWith(Orig);
Peter Collingbourne3bababf2010-08-03 16:19:16 +0000104 break;
105 }
106
107 case Intrinsic::atomic_cmp_swap: {
Chris Lattnerbdabacd2010-09-05 20:10:47 +0000108 Value *Ptr = II->getArgOperand(0);
109 Value *Cmp = II->getArgOperand(1);
110 Value *Val = II->getArgOperand(2);
Peter Collingbourne3bababf2010-08-03 16:19:16 +0000111
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);
116
Chris Lattnerbdabacd2010-09-05 20:10:47 +0000117 II->replaceAllUsesWith(Orig);
Peter Collingbourne3bababf2010-08-03 16:19:16 +0000118 break;
119 }
120
121 default:
122 return false;
123 }
124
Chris Lattnerbdabacd2010-09-05 20:10:47 +0000125 assert(II->use_empty() &&
Peter Collingbourne3bababf2010-08-03 16:19:16 +0000126 "Lowering should have eliminated any uses of the intrinsic call!");
Chris Lattnerbdabacd2010-09-05 20:10:47 +0000127 II->eraseFromParent();
Peter Collingbourne3bababf2010-08-03 16:19:16 +0000128
129 return true;
130}
131
Chris Lattnerbdabacd2010-09-05 20:10:47 +0000132namespace {
133 struct LowerAtomic : public BasicBlockPass {
134 static char ID;
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);
141 return Changed;
Peter Collingbourne3bababf2010-08-03 16:19:16 +0000142 }
Chris Lattnerbdabacd2010-09-05 20:10:47 +0000143 };
Peter Collingbourne3bababf2010-08-03 16:19:16 +0000144}
145
146char LowerAtomic::ID = 0;
Owen Anderson02dd53e2010-08-23 17:52:01 +0000147INITIALIZE_PASS(LowerAtomic, "loweratomic",
148 "Lower atomic intrinsics to non-atomic form",
149 false, false);
Peter Collingbourne3bababf2010-08-03 16:19:16 +0000150
151Pass *llvm::createLowerAtomicPass() { return new LowerAtomic(); }