blob: b41f25479a9c2629dbe7aa43ed653e885c0c0378 [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"
Peter Collingbourne3bababf2010-08-03 16:19:16 +000017#include "llvm/Function.h"
Chris Lattnerbdabacd2010-09-05 20:10:47 +000018#include "llvm/IntrinsicInst.h"
Peter Collingbourne3bababf2010-08-03 16:19:16 +000019#include "llvm/Pass.h"
20#include "llvm/Support/IRBuilder.h"
Peter Collingbourne3bababf2010-08-03 16:19:16 +000021using namespace llvm;
22
Chris Lattnerbdabacd2010-09-05 20:10:47 +000023static bool LowerAtomicIntrinsic(IntrinsicInst *II) {
24 IRBuilder<> Builder(II->getParent(), II);
25 unsigned IID = II->getIntrinsicID();
Peter Collingbourne3bababf2010-08-03 16:19:16 +000026 switch (IID) {
27 case Intrinsic::memory_barrier:
28 break;
29
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: {
Chris Lattner3ae09242010-09-05 20:13:07 +000040 Value *Ptr = II->getArgOperand(0), *Delta = II->getArgOperand(1);
Peter Collingbourne3bababf2010-08-03 16:19:16 +000041
42 LoadInst *Orig = Builder.CreateLoad(Ptr);
Nick Lewyckye52e9d62010-08-06 07:43:46 +000043 Value *Res = NULL;
Peter Collingbourne3bababf2010-08-03 16:19:16 +000044 switch (IID) {
Chris Lattner3ae09242010-09-05 20:13:07 +000045 default: assert(0 && "Unrecognized atomic modify operation");
46 case Intrinsic::atomic_load_add:
47 Res = Builder.CreateAdd(Orig, Delta);
48 break;
49 case Intrinsic::atomic_load_sub:
50 Res = Builder.CreateSub(Orig, Delta);
51 break;
52 case Intrinsic::atomic_load_and:
53 Res = Builder.CreateAnd(Orig, Delta);
54 break;
55 case Intrinsic::atomic_load_nand:
56 Res = Builder.CreateNot(Builder.CreateAnd(Orig, Delta));
57 break;
58 case Intrinsic::atomic_load_or:
59 Res = Builder.CreateOr(Orig, Delta);
60 break;
61 case Intrinsic::atomic_load_xor:
62 Res = Builder.CreateXor(Orig, Delta);
63 break;
64 case Intrinsic::atomic_load_max:
65 Res = Builder.CreateSelect(Builder.CreateICmpSLT(Orig, Delta),
66 Delta, Orig);
67 break;
68 case Intrinsic::atomic_load_min:
69 Res = Builder.CreateSelect(Builder.CreateICmpSLT(Orig, Delta),
70 Orig, Delta);
71 break;
72 case Intrinsic::atomic_load_umax:
73 Res = Builder.CreateSelect(Builder.CreateICmpULT(Orig, Delta),
74 Delta, Orig);
75 break;
76 case Intrinsic::atomic_load_umin:
77 Res = Builder.CreateSelect(Builder.CreateICmpULT(Orig, Delta),
78 Orig, Delta);
79 break;
Peter Collingbourne3bababf2010-08-03 16:19:16 +000080 }
81 Builder.CreateStore(Res, Ptr);
82
Chris Lattnerbdabacd2010-09-05 20:10:47 +000083 II->replaceAllUsesWith(Orig);
Peter Collingbourne3bababf2010-08-03 16:19:16 +000084 break;
85 }
86
87 case Intrinsic::atomic_swap: {
Chris Lattner3ae09242010-09-05 20:13:07 +000088 Value *Ptr = II->getArgOperand(0), *Val = II->getArgOperand(1);
Peter Collingbourne3bababf2010-08-03 16:19:16 +000089 LoadInst *Orig = Builder.CreateLoad(Ptr);
90 Builder.CreateStore(Val, Ptr);
Chris Lattnerbdabacd2010-09-05 20:10:47 +000091 II->replaceAllUsesWith(Orig);
Peter Collingbourne3bababf2010-08-03 16:19:16 +000092 break;
93 }
94
95 case Intrinsic::atomic_cmp_swap: {
Chris Lattner3ae09242010-09-05 20:13:07 +000096 Value *Ptr = II->getArgOperand(0), *Cmp = II->getArgOperand(1);
Chris Lattnerbdabacd2010-09-05 20:10:47 +000097 Value *Val = II->getArgOperand(2);
Peter Collingbourne3bababf2010-08-03 16:19:16 +000098
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);
Chris Lattnerbdabacd2010-09-05 20:10:47 +0000103 II->replaceAllUsesWith(Orig);
Peter Collingbourne3bababf2010-08-03 16:19:16 +0000104 break;
105 }
106
107 default:
108 return false;
109 }
110
Chris Lattnerbdabacd2010-09-05 20:10:47 +0000111 assert(II->use_empty() &&
Peter Collingbourne3bababf2010-08-03 16:19:16 +0000112 "Lowering should have eliminated any uses of the intrinsic call!");
Chris Lattnerbdabacd2010-09-05 20:10:47 +0000113 II->eraseFromParent();
Peter Collingbourne3bababf2010-08-03 16:19:16 +0000114
115 return true;
116}
117
Chris Lattnerbdabacd2010-09-05 20:10:47 +0000118namespace {
119 struct LowerAtomic : public BasicBlockPass {
120 static char ID;
121 LowerAtomic() : BasicBlockPass(ID) {}
122 bool runOnBasicBlock(BasicBlock &BB) {
123 bool Changed = false;
124 for (BasicBlock::iterator DI = BB.begin(), DE = BB.end(); DI != DE; )
125 if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(DI++))
126 Changed |= LowerAtomicIntrinsic(II);
127 return Changed;
Peter Collingbourne3bababf2010-08-03 16:19:16 +0000128 }
Chris Lattnerbdabacd2010-09-05 20:10:47 +0000129 };
Peter Collingbourne3bababf2010-08-03 16:19:16 +0000130}
131
132char LowerAtomic::ID = 0;
Owen Anderson02dd53e2010-08-23 17:52:01 +0000133INITIALIZE_PASS(LowerAtomic, "loweratomic",
134 "Lower atomic intrinsics to non-atomic form",
Owen Andersonce665bd2010-10-07 22:25:06 +0000135 false, false)
Peter Collingbourne3bababf2010-08-03 16:19:16 +0000136
137Pass *llvm::createLowerAtomicPass() { return new LowerAtomic(); }