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