| //===- LowerAtomic.cpp - Lower atomic intrinsics --------------------------===// | 
 | // | 
 | //                     The LLVM Compiler Infrastructure | 
 | // | 
 | // This file is distributed under the University of Illinois Open Source | 
 | // License. See LICENSE.TXT for details. | 
 | // | 
 | //===----------------------------------------------------------------------===// | 
 | // | 
 | // This pass lowers atomic intrinsics to non-atomic form for use in a known | 
 | // non-preemptible environment. | 
 | // | 
 | //===----------------------------------------------------------------------===// | 
 |  | 
 | #define DEBUG_TYPE "loweratomic" | 
 | #include "llvm/Transforms/Scalar.h" | 
 | #include "llvm/IR/Function.h" | 
 | #include "llvm/IR/IRBuilder.h" | 
 | #include "llvm/IR/IntrinsicInst.h" | 
 | #include "llvm/Pass.h" | 
 | using namespace llvm; | 
 |  | 
 | static bool LowerAtomicCmpXchgInst(AtomicCmpXchgInst *CXI) { | 
 |   IRBuilder<> Builder(CXI->getParent(), CXI); | 
 |   Value *Ptr = CXI->getPointerOperand(); | 
 |   Value *Cmp = CXI->getCompareOperand(); | 
 |   Value *Val = CXI->getNewValOperand(); | 
 |  | 
 |   LoadInst *Orig = Builder.CreateLoad(Ptr); | 
 |   Value *Equal = Builder.CreateICmpEQ(Orig, Cmp); | 
 |   Value *Res = Builder.CreateSelect(Equal, Val, Orig); | 
 |   Builder.CreateStore(Res, Ptr); | 
 |  | 
 |   CXI->replaceAllUsesWith(Orig); | 
 |   CXI->eraseFromParent(); | 
 |   return true; | 
 | } | 
 |  | 
 | static bool LowerAtomicRMWInst(AtomicRMWInst *RMWI) { | 
 |   IRBuilder<> Builder(RMWI->getParent(), RMWI); | 
 |   Value *Ptr = RMWI->getPointerOperand(); | 
 |   Value *Val = RMWI->getValOperand(); | 
 |  | 
 |   LoadInst *Orig = Builder.CreateLoad(Ptr); | 
 |   Value *Res = NULL; | 
 |  | 
 |   switch (RMWI->getOperation()) { | 
 |   default: llvm_unreachable("Unexpected RMW operation"); | 
 |   case AtomicRMWInst::Xchg: | 
 |     Res = Val; | 
 |     break; | 
 |   case AtomicRMWInst::Add: | 
 |     Res = Builder.CreateAdd(Orig, Val); | 
 |     break; | 
 |   case AtomicRMWInst::Sub: | 
 |     Res = Builder.CreateSub(Orig, Val); | 
 |     break; | 
 |   case AtomicRMWInst::And: | 
 |     Res = Builder.CreateAnd(Orig, Val); | 
 |     break; | 
 |   case AtomicRMWInst::Nand: | 
 |     Res = Builder.CreateNot(Builder.CreateAnd(Orig, Val)); | 
 |     break; | 
 |   case AtomicRMWInst::Or: | 
 |     Res = Builder.CreateOr(Orig, Val); | 
 |     break; | 
 |   case AtomicRMWInst::Xor: | 
 |     Res = Builder.CreateXor(Orig, Val); | 
 |     break; | 
 |   case AtomicRMWInst::Max: | 
 |     Res = Builder.CreateSelect(Builder.CreateICmpSLT(Orig, Val), | 
 |                                Val, Orig); | 
 |     break; | 
 |   case AtomicRMWInst::Min: | 
 |     Res = Builder.CreateSelect(Builder.CreateICmpSLT(Orig, Val), | 
 |                                Orig, Val); | 
 |     break; | 
 |   case AtomicRMWInst::UMax: | 
 |     Res = Builder.CreateSelect(Builder.CreateICmpULT(Orig, Val), | 
 |                                Val, Orig); | 
 |     break; | 
 |   case AtomicRMWInst::UMin: | 
 |     Res = Builder.CreateSelect(Builder.CreateICmpULT(Orig, Val), | 
 |                                Orig, Val); | 
 |     break; | 
 |   } | 
 |   Builder.CreateStore(Res, Ptr); | 
 |   RMWI->replaceAllUsesWith(Orig); | 
 |   RMWI->eraseFromParent(); | 
 |   return true; | 
 | } | 
 |  | 
 | static bool LowerFenceInst(FenceInst *FI) { | 
 |   FI->eraseFromParent(); | 
 |   return true; | 
 | } | 
 |  | 
 | static bool LowerLoadInst(LoadInst *LI) { | 
 |   LI->setAtomic(NotAtomic); | 
 |   return true; | 
 | } | 
 |  | 
 | static bool LowerStoreInst(StoreInst *SI) { | 
 |   SI->setAtomic(NotAtomic); | 
 |   return true; | 
 | } | 
 |  | 
 | namespace { | 
 |   struct LowerAtomic : public BasicBlockPass { | 
 |     static char ID; | 
 |     LowerAtomic() : BasicBlockPass(ID) { | 
 |       initializeLowerAtomicPass(*PassRegistry::getPassRegistry()); | 
 |     } | 
 |     bool runOnBasicBlock(BasicBlock &BB) { | 
 |       bool Changed = false; | 
 |       for (BasicBlock::iterator DI = BB.begin(), DE = BB.end(); DI != DE; ) { | 
 |         Instruction *Inst = DI++; | 
 |         if (FenceInst *FI = dyn_cast<FenceInst>(Inst)) | 
 |           Changed |= LowerFenceInst(FI); | 
 |         else if (AtomicCmpXchgInst *CXI = dyn_cast<AtomicCmpXchgInst>(Inst)) | 
 |           Changed |= LowerAtomicCmpXchgInst(CXI); | 
 |         else if (AtomicRMWInst *RMWI = dyn_cast<AtomicRMWInst>(Inst)) | 
 |           Changed |= LowerAtomicRMWInst(RMWI); | 
 |         else if (LoadInst *LI = dyn_cast<LoadInst>(Inst)) { | 
 |           if (LI->isAtomic()) | 
 |             LowerLoadInst(LI); | 
 |         } else if (StoreInst *SI = dyn_cast<StoreInst>(Inst)) { | 
 |           if (SI->isAtomic()) | 
 |             LowerStoreInst(SI); | 
 |         } | 
 |       } | 
 |       return Changed; | 
 |     } | 
 |   }; | 
 | } | 
 |  | 
 | char LowerAtomic::ID = 0; | 
 | INITIALIZE_PASS(LowerAtomic, "loweratomic", | 
 |                 "Lower atomic intrinsics to non-atomic form", | 
 |                 false, false) | 
 |  | 
 | Pass *llvm::createLowerAtomicPass() { return new LowerAtomic(); } |