LowerAtomic.cpp revision dce4a407a24b04eebc6a376f8e62b41aaa7b071f
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#include "llvm/Transforms/Scalar.h" 16#include "llvm/IR/Function.h" 17#include "llvm/IR/IRBuilder.h" 18#include "llvm/IR/IntrinsicInst.h" 19#include "llvm/Pass.h" 20using namespace llvm; 21 22#define DEBUG_TYPE "loweratomic" 23 24static bool LowerAtomicCmpXchgInst(AtomicCmpXchgInst *CXI) { 25 IRBuilder<> Builder(CXI->getParent(), CXI); 26 Value *Ptr = CXI->getPointerOperand(); 27 Value *Cmp = CXI->getCompareOperand(); 28 Value *Val = CXI->getNewValOperand(); 29 30 LoadInst *Orig = Builder.CreateLoad(Ptr); 31 Value *Equal = Builder.CreateICmpEQ(Orig, Cmp); 32 Value *Res = Builder.CreateSelect(Equal, Val, Orig); 33 Builder.CreateStore(Res, Ptr); 34 35 CXI->replaceAllUsesWith(Orig); 36 CXI->eraseFromParent(); 37 return true; 38} 39 40static bool LowerAtomicRMWInst(AtomicRMWInst *RMWI) { 41 IRBuilder<> Builder(RMWI->getParent(), RMWI); 42 Value *Ptr = RMWI->getPointerOperand(); 43 Value *Val = RMWI->getValOperand(); 44 45 LoadInst *Orig = Builder.CreateLoad(Ptr); 46 Value *Res = nullptr; 47 48 switch (RMWI->getOperation()) { 49 default: llvm_unreachable("Unexpected RMW operation"); 50 case AtomicRMWInst::Xchg: 51 Res = Val; 52 break; 53 case AtomicRMWInst::Add: 54 Res = Builder.CreateAdd(Orig, Val); 55 break; 56 case AtomicRMWInst::Sub: 57 Res = Builder.CreateSub(Orig, Val); 58 break; 59 case AtomicRMWInst::And: 60 Res = Builder.CreateAnd(Orig, Val); 61 break; 62 case AtomicRMWInst::Nand: 63 Res = Builder.CreateNot(Builder.CreateAnd(Orig, Val)); 64 break; 65 case AtomicRMWInst::Or: 66 Res = Builder.CreateOr(Orig, Val); 67 break; 68 case AtomicRMWInst::Xor: 69 Res = Builder.CreateXor(Orig, Val); 70 break; 71 case AtomicRMWInst::Max: 72 Res = Builder.CreateSelect(Builder.CreateICmpSLT(Orig, Val), 73 Val, Orig); 74 break; 75 case AtomicRMWInst::Min: 76 Res = Builder.CreateSelect(Builder.CreateICmpSLT(Orig, Val), 77 Orig, Val); 78 break; 79 case AtomicRMWInst::UMax: 80 Res = Builder.CreateSelect(Builder.CreateICmpULT(Orig, Val), 81 Val, Orig); 82 break; 83 case AtomicRMWInst::UMin: 84 Res = Builder.CreateSelect(Builder.CreateICmpULT(Orig, Val), 85 Orig, Val); 86 break; 87 } 88 Builder.CreateStore(Res, Ptr); 89 RMWI->replaceAllUsesWith(Orig); 90 RMWI->eraseFromParent(); 91 return true; 92} 93 94static bool LowerFenceInst(FenceInst *FI) { 95 FI->eraseFromParent(); 96 return true; 97} 98 99static bool LowerLoadInst(LoadInst *LI) { 100 LI->setAtomic(NotAtomic); 101 return true; 102} 103 104static bool LowerStoreInst(StoreInst *SI) { 105 SI->setAtomic(NotAtomic); 106 return true; 107} 108 109namespace { 110 struct LowerAtomic : public BasicBlockPass { 111 static char ID; 112 LowerAtomic() : BasicBlockPass(ID) { 113 initializeLowerAtomicPass(*PassRegistry::getPassRegistry()); 114 } 115 bool runOnBasicBlock(BasicBlock &BB) override { 116 if (skipOptnoneFunction(BB)) 117 return false; 118 bool Changed = false; 119 for (BasicBlock::iterator DI = BB.begin(), DE = BB.end(); DI != DE; ) { 120 Instruction *Inst = DI++; 121 if (FenceInst *FI = dyn_cast<FenceInst>(Inst)) 122 Changed |= LowerFenceInst(FI); 123 else if (AtomicCmpXchgInst *CXI = dyn_cast<AtomicCmpXchgInst>(Inst)) 124 Changed |= LowerAtomicCmpXchgInst(CXI); 125 else if (AtomicRMWInst *RMWI = dyn_cast<AtomicRMWInst>(Inst)) 126 Changed |= LowerAtomicRMWInst(RMWI); 127 else if (LoadInst *LI = dyn_cast<LoadInst>(Inst)) { 128 if (LI->isAtomic()) 129 LowerLoadInst(LI); 130 } else if (StoreInst *SI = dyn_cast<StoreInst>(Inst)) { 131 if (SI->isAtomic()) 132 LowerStoreInst(SI); 133 } 134 } 135 return Changed; 136 } 137 }; 138} 139 140char LowerAtomic::ID = 0; 141INITIALIZE_PASS(LowerAtomic, "loweratomic", 142 "Lower atomic intrinsics to non-atomic form", 143 false, false) 144 145Pass *llvm::createLowerAtomicPass() { return new LowerAtomic(); } 146