LowerAtomic.cpp revision 36b56886974eae4f9c5ebc96befd3e7bfe5de338
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/IR/Function.h"
18#include "llvm/IR/IRBuilder.h"
19#include "llvm/IR/IntrinsicInst.h"
20#include "llvm/Pass.h"
21using namespace llvm;
22
23static 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
39static 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
93static bool LowerFenceInst(FenceInst *FI) {
94  FI->eraseFromParent();
95  return true;
96}
97
98static bool LowerLoadInst(LoadInst *LI) {
99  LI->setAtomic(NotAtomic);
100  return true;
101}
102
103static bool LowerStoreInst(StoreInst *SI) {
104  SI->setAtomic(NotAtomic);
105  return true;
106}
107
108namespace {
109  struct LowerAtomic : public BasicBlockPass {
110    static char ID;
111    LowerAtomic() : BasicBlockPass(ID) {
112      initializeLowerAtomicPass(*PassRegistry::getPassRegistry());
113    }
114    bool runOnBasicBlock(BasicBlock &BB) override {
115      if (skipOptnoneFunction(BB))
116        return false;
117      bool Changed = false;
118      for (BasicBlock::iterator DI = BB.begin(), DE = BB.end(); DI != DE; ) {
119        Instruction *Inst = DI++;
120        if (FenceInst *FI = dyn_cast<FenceInst>(Inst))
121          Changed |= LowerFenceInst(FI);
122        else if (AtomicCmpXchgInst *CXI = dyn_cast<AtomicCmpXchgInst>(Inst))
123          Changed |= LowerAtomicCmpXchgInst(CXI);
124        else if (AtomicRMWInst *RMWI = dyn_cast<AtomicRMWInst>(Inst))
125          Changed |= LowerAtomicRMWInst(RMWI);
126        else if (LoadInst *LI = dyn_cast<LoadInst>(Inst)) {
127          if (LI->isAtomic())
128            LowerLoadInst(LI);
129        } else if (StoreInst *SI = dyn_cast<StoreInst>(Inst)) {
130          if (SI->isAtomic())
131            LowerStoreInst(SI);
132        }
133      }
134      return Changed;
135    }
136  };
137}
138
139char LowerAtomic::ID = 0;
140INITIALIZE_PASS(LowerAtomic, "loweratomic",
141                "Lower atomic intrinsics to non-atomic form",
142                false, false)
143
144Pass *llvm::createLowerAtomicPass() { return new LowerAtomic(); }
145