LowerAtomic.cpp revision 8a552bb85a5e9a6c250c0a899941fbd3ae7b5006
1//===- 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/Function.h" 18#include "llvm/IntrinsicInst.h" 19#include "llvm/Pass.h" 20#include "llvm/Support/IRBuilder.h" 21using namespace llvm; 22 23static bool LowerAtomicIntrinsic(IntrinsicInst *II) { 24 IRBuilder<> Builder(II->getParent(), II); 25 unsigned IID = II->getIntrinsicID(); 26 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: { 40 Value *Ptr = II->getArgOperand(0), *Delta = II->getArgOperand(1); 41 42 LoadInst *Orig = Builder.CreateLoad(Ptr); 43 Value *Res = NULL; 44 switch (IID) { 45 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; 80 } 81 Builder.CreateStore(Res, Ptr); 82 83 II->replaceAllUsesWith(Orig); 84 break; 85 } 86 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); 92 break; 93 } 94 95 case Intrinsic::atomic_cmp_swap: { 96 Value *Ptr = II->getArgOperand(0), *Cmp = II->getArgOperand(1); 97 Value *Val = II->getArgOperand(2); 98 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); 104 break; 105 } 106 107 default: 108 return false; 109 } 110 111 assert(II->use_empty() && 112 "Lowering should have eliminated any uses of the intrinsic call!"); 113 II->eraseFromParent(); 114 115 return true; 116} 117 118static bool LowerFenceInst(FenceInst *FI) { 119 FI->eraseFromParent(); 120 return true; 121} 122 123namespace { 124 struct LowerAtomic : public BasicBlockPass { 125 static char ID; 126 LowerAtomic() : BasicBlockPass(ID) { 127 initializeLowerAtomicPass(*PassRegistry::getPassRegistry()); 128 } 129 bool runOnBasicBlock(BasicBlock &BB) { 130 bool Changed = false; 131 for (BasicBlock::iterator DI = BB.begin(), DE = BB.end(); DI != DE; ) { 132 Instruction *Inst = DI++; 133 if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(Inst)) 134 Changed |= LowerAtomicIntrinsic(II); 135 if (FenceInst *FI = dyn_cast<FenceInst>(Inst)) 136 Changed |= LowerFenceInst(FI); 137 } 138 return Changed; 139 } 140 }; 141} 142 143char LowerAtomic::ID = 0; 144INITIALIZE_PASS(LowerAtomic, "loweratomic", 145 "Lower atomic intrinsics to non-atomic form", 146 false, false) 147 148Pass *llvm::createLowerAtomicPass() { return new LowerAtomic(); } 149