LowerAtomic.cpp revision 212904
1252190Srpaulo//===- LowerAtomic.cpp - Lower atomic intrinsics --------------------------===// 2252190Srpaulo// 3252190Srpaulo// The LLVM Compiler Infrastructure 4252190Srpaulo// 5252190Srpaulo// This file is distributed under the University of Illinois Open Source 6252190Srpaulo// License. See LICENSE.TXT for details. 7252190Srpaulo// 8252190Srpaulo//===----------------------------------------------------------------------===// 9252190Srpaulo// 10252190Srpaulo// This pass lowers atomic intrinsics to non-atomic form for use in a known 11252190Srpaulo// non-preemptible environment. 12252190Srpaulo// 13252190Srpaulo//===----------------------------------------------------------------------===// 14252190Srpaulo 15252190Srpaulo#define DEBUG_TYPE "loweratomic" 16252190Srpaulo#include "llvm/Transforms/Scalar.h" 17252190Srpaulo#include "llvm/BasicBlock.h" 18252190Srpaulo#include "llvm/Function.h" 19252190Srpaulo#include "llvm/Instruction.h" 20252190Srpaulo#include "llvm/Instructions.h" 21252190Srpaulo#include "llvm/Intrinsics.h" 22252190Srpaulo#include "llvm/Pass.h" 23252190Srpaulo#include "llvm/Support/IRBuilder.h" 24252190Srpaulo 25252190Srpaulousing namespace llvm; 26252190Srpaulo 27252190Srpaulonamespace { 28252190Srpaulo 29252190Srpaulobool LowerAtomicIntrinsic(CallInst *CI) { 30252190Srpaulo IRBuilder<> Builder(CI->getParent(), CI); 31252190Srpaulo 32252190Srpaulo Function *Callee = CI->getCalledFunction(); 33252190Srpaulo if (!Callee) 34252190Srpaulo return false; 35252190Srpaulo 36252190Srpaulo unsigned IID = Callee->getIntrinsicID(); 37252190Srpaulo switch (IID) { 38252190Srpaulo case Intrinsic::memory_barrier: 39252190Srpaulo break; 40252190Srpaulo 41252190Srpaulo case Intrinsic::atomic_load_add: 42252190Srpaulo case Intrinsic::atomic_load_sub: 43252190Srpaulo case Intrinsic::atomic_load_and: 44252190Srpaulo case Intrinsic::atomic_load_nand: 45252190Srpaulo case Intrinsic::atomic_load_or: 46252190Srpaulo case Intrinsic::atomic_load_xor: 47252190Srpaulo case Intrinsic::atomic_load_max: 48252190Srpaulo case Intrinsic::atomic_load_min: 49252190Srpaulo case Intrinsic::atomic_load_umax: 50252190Srpaulo case Intrinsic::atomic_load_umin: { 51252190Srpaulo Value *Ptr = CI->getArgOperand(0); 52252190Srpaulo Value *Delta = CI->getArgOperand(1); 53252190Srpaulo 54252190Srpaulo LoadInst *Orig = Builder.CreateLoad(Ptr); 55252190Srpaulo Value *Res = NULL; 56252190Srpaulo switch (IID) { 57252190Srpaulo default: assert(0 && "Unrecognized atomic modify operation"); 58252190Srpaulo case Intrinsic::atomic_load_add: 59252190Srpaulo Res = Builder.CreateAdd(Orig, Delta); 60252190Srpaulo break; 61252190Srpaulo case Intrinsic::atomic_load_sub: 62252190Srpaulo Res = Builder.CreateSub(Orig, Delta); 63252190Srpaulo break; 64252190Srpaulo case Intrinsic::atomic_load_and: 65252190Srpaulo Res = Builder.CreateAnd(Orig, Delta); 66252190Srpaulo break; 67252190Srpaulo case Intrinsic::atomic_load_nand: 68252190Srpaulo Res = Builder.CreateNot(Builder.CreateAnd(Orig, Delta)); 69252190Srpaulo break; 70252190Srpaulo case Intrinsic::atomic_load_or: 71252190Srpaulo Res = Builder.CreateOr(Orig, Delta); 72281806Srpaulo break; 73281806Srpaulo case Intrinsic::atomic_load_xor: 74281806Srpaulo Res = Builder.CreateXor(Orig, Delta); 75281806Srpaulo break; 76281806Srpaulo case Intrinsic::atomic_load_max: 77281806Srpaulo Res = Builder.CreateSelect(Builder.CreateICmpSLT(Orig, Delta), 78281806Srpaulo Delta, 79281806Srpaulo Orig); 80281806Srpaulo break; 81281806Srpaulo case Intrinsic::atomic_load_min: 82281806Srpaulo Res = Builder.CreateSelect(Builder.CreateICmpSLT(Orig, Delta), 83252190Srpaulo Orig, 84252190Srpaulo Delta); 85252190Srpaulo break; 86252190Srpaulo case Intrinsic::atomic_load_umax: 87252190Srpaulo Res = Builder.CreateSelect(Builder.CreateICmpULT(Orig, Delta), 88281806Srpaulo Delta, 89281806Srpaulo Orig); 90281806Srpaulo break; 91281806Srpaulo case Intrinsic::atomic_load_umin: 92281806Srpaulo Res = Builder.CreateSelect(Builder.CreateICmpULT(Orig, Delta), 93281806Srpaulo Orig, 94281806Srpaulo Delta); 95281806Srpaulo break; 96281806Srpaulo } 97281806Srpaulo Builder.CreateStore(Res, Ptr); 98281806Srpaulo 99281806Srpaulo CI->replaceAllUsesWith(Orig); 100281806Srpaulo break; 101281806Srpaulo } 102281806Srpaulo 103281806Srpaulo case Intrinsic::atomic_swap: { 104281806Srpaulo Value *Ptr = CI->getArgOperand(0); 105281806Srpaulo Value *Val = CI->getArgOperand(1); 106281806Srpaulo 107281806Srpaulo LoadInst *Orig = Builder.CreateLoad(Ptr); 108281806Srpaulo Builder.CreateStore(Val, Ptr); 109281806Srpaulo 110281806Srpaulo CI->replaceAllUsesWith(Orig); 111281806Srpaulo break; 112281806Srpaulo } 113281806Srpaulo 114281806Srpaulo case Intrinsic::atomic_cmp_swap: { 115281806Srpaulo Value *Ptr = CI->getArgOperand(0); 116281806Srpaulo Value *Cmp = CI->getArgOperand(1); 117281806Srpaulo Value *Val = CI->getArgOperand(2); 118281806Srpaulo 119281806Srpaulo LoadInst *Orig = Builder.CreateLoad(Ptr); 120281806Srpaulo Value *Equal = Builder.CreateICmpEQ(Orig, Cmp); 121281806Srpaulo Value *Res = Builder.CreateSelect(Equal, Val, Orig); 122281806Srpaulo Builder.CreateStore(Res, Ptr); 123281806Srpaulo 124281806Srpaulo CI->replaceAllUsesWith(Orig); 125281806Srpaulo break; 126281806Srpaulo } 127281806Srpaulo 128281806Srpaulo default: 129281806Srpaulo return false; 130281806Srpaulo } 131281806Srpaulo 132281806Srpaulo assert(CI->use_empty() && 133281806Srpaulo "Lowering should have eliminated any uses of the intrinsic call!"); 134281806Srpaulo CI->eraseFromParent(); 135281806Srpaulo 136281806Srpaulo return true; 137281806Srpaulo} 138281806Srpaulo 139281806Srpaulostruct LowerAtomic : public BasicBlockPass { 140281806Srpaulo static char ID; 141281806Srpaulo LowerAtomic() : BasicBlockPass(ID) {} 142281806Srpaulo bool runOnBasicBlock(BasicBlock &BB) { 143281806Srpaulo bool Changed = false; 144281806Srpaulo for (BasicBlock::iterator DI = BB.begin(), DE = BB.end(); DI != DE; ) { 145281806Srpaulo Instruction *Inst = DI++; 146281806Srpaulo if (CallInst *CI = dyn_cast<CallInst>(Inst)) 147281806Srpaulo Changed |= LowerAtomicIntrinsic(CI); 148281806Srpaulo } 149281806Srpaulo return Changed; 150281806Srpaulo } 151281806Srpaulo 152281806Srpaulo}; 153281806Srpaulo 154281806Srpaulo} 155281806Srpaulo 156281806Srpaulochar LowerAtomic::ID = 0; 157281806SrpauloINITIALIZE_PASS(LowerAtomic, "loweratomic", 158281806Srpaulo "Lower atomic intrinsics to non-atomic form", 159281806Srpaulo false, false); 160281806Srpaulo 161281806SrpauloPass *llvm::createLowerAtomicPass() { return new LowerAtomic(); } 162281806Srpaulo