1212793Sdim//===- LowerAtomic.cpp - Lower atomic intrinsics --------------------------===// 2212793Sdim// 3212793Sdim// The LLVM Compiler Infrastructure 4212793Sdim// 5212793Sdim// This file is distributed under the University of Illinois Open Source 6212793Sdim// License. See LICENSE.TXT for details. 7212793Sdim// 8212793Sdim//===----------------------------------------------------------------------===// 9212793Sdim// 10212793Sdim// This pass lowers atomic intrinsics to non-atomic form for use in a known 11212793Sdim// non-preemptible environment. 12212793Sdim// 13212793Sdim//===----------------------------------------------------------------------===// 14212793Sdim 15212793Sdim#define DEBUG_TYPE "loweratomic" 16212793Sdim#include "llvm/Transforms/Scalar.h" 17252723Sdim#include "llvm/IR/Function.h" 18252723Sdim#include "llvm/IR/IRBuilder.h" 19252723Sdim#include "llvm/IR/IntrinsicInst.h" 20212793Sdim#include "llvm/Pass.h" 21212793Sdimusing namespace llvm; 22212793Sdim 23226890Sdimstatic bool LowerAtomicCmpXchgInst(AtomicCmpXchgInst *CXI) { 24226890Sdim IRBuilder<> Builder(CXI->getParent(), CXI); 25226890Sdim Value *Ptr = CXI->getPointerOperand(); 26226890Sdim Value *Cmp = CXI->getCompareOperand(); 27226890Sdim Value *Val = CXI->getNewValOperand(); 28245431Sdim 29226890Sdim LoadInst *Orig = Builder.CreateLoad(Ptr); 30226890Sdim Value *Equal = Builder.CreateICmpEQ(Orig, Cmp); 31226890Sdim Value *Res = Builder.CreateSelect(Equal, Val, Orig); 32226890Sdim Builder.CreateStore(Res, Ptr); 33245431Sdim 34226890Sdim CXI->replaceAllUsesWith(Orig); 35226890Sdim CXI->eraseFromParent(); 36226890Sdim return true; 37226890Sdim} 38212793Sdim 39226890Sdimstatic bool LowerAtomicRMWInst(AtomicRMWInst *RMWI) { 40226890Sdim IRBuilder<> Builder(RMWI->getParent(), RMWI); 41226890Sdim Value *Ptr = RMWI->getPointerOperand(); 42226890Sdim Value *Val = RMWI->getValOperand(); 43212793Sdim 44226890Sdim LoadInst *Orig = Builder.CreateLoad(Ptr); 45226890Sdim Value *Res = NULL; 46212793Sdim 47226890Sdim switch (RMWI->getOperation()) { 48226890Sdim default: llvm_unreachable("Unexpected RMW operation"); 49226890Sdim case AtomicRMWInst::Xchg: 50226890Sdim Res = Val; 51212793Sdim break; 52226890Sdim case AtomicRMWInst::Add: 53226890Sdim Res = Builder.CreateAdd(Orig, Val); 54212793Sdim break; 55226890Sdim case AtomicRMWInst::Sub: 56226890Sdim Res = Builder.CreateSub(Orig, Val); 57212793Sdim break; 58226890Sdim case AtomicRMWInst::And: 59226890Sdim Res = Builder.CreateAnd(Orig, Val); 60226890Sdim break; 61226890Sdim case AtomicRMWInst::Nand: 62226890Sdim Res = Builder.CreateNot(Builder.CreateAnd(Orig, Val)); 63226890Sdim break; 64226890Sdim case AtomicRMWInst::Or: 65226890Sdim Res = Builder.CreateOr(Orig, Val); 66226890Sdim break; 67226890Sdim case AtomicRMWInst::Xor: 68226890Sdim Res = Builder.CreateXor(Orig, Val); 69226890Sdim break; 70226890Sdim case AtomicRMWInst::Max: 71226890Sdim Res = Builder.CreateSelect(Builder.CreateICmpSLT(Orig, Val), 72226890Sdim Val, Orig); 73226890Sdim break; 74226890Sdim case AtomicRMWInst::Min: 75226890Sdim Res = Builder.CreateSelect(Builder.CreateICmpSLT(Orig, Val), 76226890Sdim Orig, Val); 77226890Sdim break; 78226890Sdim case AtomicRMWInst::UMax: 79226890Sdim Res = Builder.CreateSelect(Builder.CreateICmpULT(Orig, Val), 80226890Sdim Val, Orig); 81226890Sdim break; 82226890Sdim case AtomicRMWInst::UMin: 83226890Sdim Res = Builder.CreateSelect(Builder.CreateICmpULT(Orig, Val), 84226890Sdim Orig, Val); 85226890Sdim break; 86212793Sdim } 87226890Sdim Builder.CreateStore(Res, Ptr); 88226890Sdim RMWI->replaceAllUsesWith(Orig); 89226890Sdim RMWI->eraseFromParent(); 90226890Sdim return true; 91226890Sdim} 92212793Sdim 93226890Sdimstatic bool LowerFenceInst(FenceInst *FI) { 94226890Sdim FI->eraseFromParent(); 95226890Sdim return true; 96226890Sdim} 97212793Sdim 98226890Sdimstatic bool LowerLoadInst(LoadInst *LI) { 99226890Sdim LI->setAtomic(NotAtomic); 100226890Sdim return true; 101226890Sdim} 102212793Sdim 103226890Sdimstatic bool LowerStoreInst(StoreInst *SI) { 104226890Sdim SI->setAtomic(NotAtomic); 105212793Sdim return true; 106212793Sdim} 107212793Sdim 108218893Sdimnamespace { 109218893Sdim struct LowerAtomic : public BasicBlockPass { 110218893Sdim static char ID; 111218893Sdim LowerAtomic() : BasicBlockPass(ID) { 112218893Sdim initializeLowerAtomicPass(*PassRegistry::getPassRegistry()); 113212793Sdim } 114218893Sdim bool runOnBasicBlock(BasicBlock &BB) { 115218893Sdim bool Changed = false; 116226890Sdim for (BasicBlock::iterator DI = BB.begin(), DE = BB.end(); DI != DE; ) { 117226890Sdim Instruction *Inst = DI++; 118226890Sdim if (FenceInst *FI = dyn_cast<FenceInst>(Inst)) 119226890Sdim Changed |= LowerFenceInst(FI); 120226890Sdim else if (AtomicCmpXchgInst *CXI = dyn_cast<AtomicCmpXchgInst>(Inst)) 121226890Sdim Changed |= LowerAtomicCmpXchgInst(CXI); 122226890Sdim else if (AtomicRMWInst *RMWI = dyn_cast<AtomicRMWInst>(Inst)) 123226890Sdim Changed |= LowerAtomicRMWInst(RMWI); 124226890Sdim else if (LoadInst *LI = dyn_cast<LoadInst>(Inst)) { 125226890Sdim if (LI->isAtomic()) 126226890Sdim LowerLoadInst(LI); 127226890Sdim } else if (StoreInst *SI = dyn_cast<StoreInst>(Inst)) { 128226890Sdim if (SI->isAtomic()) 129226890Sdim LowerStoreInst(SI); 130226890Sdim } 131226890Sdim } 132218893Sdim return Changed; 133218893Sdim } 134218893Sdim }; 135212793Sdim} 136212793Sdim 137212793Sdimchar LowerAtomic::ID = 0; 138212793SdimINITIALIZE_PASS(LowerAtomic, "loweratomic", 139212793Sdim "Lower atomic intrinsics to non-atomic form", 140218893Sdim false, false) 141212793Sdim 142212793SdimPass *llvm::createLowerAtomicPass() { return new LowerAtomic(); } 143