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/BasicBlock.h" 18 #include "llvm/Function.h" 19 #include "llvm/Instruction.h" 20 #include "llvm/Instructions.h" 21 #include "llvm/Intrinsics.h" 22 #include "llvm/Pass.h" 23 #include "llvm/Support/IRBuilder.h" 24 25 using namespace llvm; 26 27 namespace { 28 29 bool LowerAtomicIntrinsic(CallInst *CI) { 30 IRBuilder<> Builder(CI->getParent(), CI); 31 32 Function *Callee = CI->getCalledFunction(); 33 if (!Callee) 34 return false; 35 36 unsigned IID = Callee->getIntrinsicID(); 37 switch (IID) { 38 case Intrinsic::memory_barrier: 39 break; 40 41 case Intrinsic::atomic_load_add: 42 case Intrinsic::atomic_load_sub: 43 case Intrinsic::atomic_load_and: 44 case Intrinsic::atomic_load_nand: 45 case Intrinsic::atomic_load_or: 46 case Intrinsic::atomic_load_xor: 47 case Intrinsic::atomic_load_max: 48 case Intrinsic::atomic_load_min: 49 case Intrinsic::atomic_load_umax: 50 case Intrinsic::atomic_load_umin: { 51 Value *Ptr = CI->getArgOperand(0); 52 Value *Delta = CI->getArgOperand(1); 53 54 LoadInst *Orig = Builder.CreateLoad(Ptr); 55 Value *Res = NULL; 56 switch (IID) { 57 default: assert(0 && "Unrecognized atomic modify operation"); 58 case Intrinsic::atomic_load_add: 59 Res = Builder.CreateAdd(Orig, Delta); 60 break; 61 case Intrinsic::atomic_load_sub: 62 Res = Builder.CreateSub(Orig, Delta); 63 break; 64 case Intrinsic::atomic_load_and: 65 Res = Builder.CreateAnd(Orig, Delta); 66 break; 67 case Intrinsic::atomic_load_nand: 68 Res = Builder.CreateNot(Builder.CreateAnd(Orig, Delta)); 69 break; 70 case Intrinsic::atomic_load_or: 71 Res = Builder.CreateOr(Orig, Delta); 72 break; 73 case Intrinsic::atomic_load_xor: 74 Res = Builder.CreateXor(Orig, Delta); 75 break; 76 case Intrinsic::atomic_load_max: 77 Res = Builder.CreateSelect(Builder.CreateICmpSLT(Orig, Delta), 78 Delta, 79 Orig); 80 break; 81 case Intrinsic::atomic_load_min: 82 Res = Builder.CreateSelect(Builder.CreateICmpSLT(Orig, Delta), 83 Orig, 84 Delta); 85 break; 86 case Intrinsic::atomic_load_umax: 87 Res = Builder.CreateSelect(Builder.CreateICmpULT(Orig, Delta), 88 Delta, 89 Orig); 90 break; 91 case Intrinsic::atomic_load_umin: 92 Res = Builder.CreateSelect(Builder.CreateICmpULT(Orig, Delta), 93 Orig, 94 Delta); 95 break; 96 } 97 Builder.CreateStore(Res, Ptr); 98 99 CI->replaceAllUsesWith(Orig); 100 break; 101 } 102 103 case Intrinsic::atomic_swap: { 104 Value *Ptr = CI->getArgOperand(0); 105 Value *Val = CI->getArgOperand(1); 106 107 LoadInst *Orig = Builder.CreateLoad(Ptr); 108 Builder.CreateStore(Val, Ptr); 109 110 CI->replaceAllUsesWith(Orig); 111 break; 112 } 113 114 case Intrinsic::atomic_cmp_swap: { 115 Value *Ptr = CI->getArgOperand(0); 116 Value *Cmp = CI->getArgOperand(1); 117 Value *Val = CI->getArgOperand(2); 118 119 LoadInst *Orig = Builder.CreateLoad(Ptr); 120 Value *Equal = Builder.CreateICmpEQ(Orig, Cmp); 121 Value *Res = Builder.CreateSelect(Equal, Val, Orig); 122 Builder.CreateStore(Res, Ptr); 123 124 CI->replaceAllUsesWith(Orig); 125 break; 126 } 127 128 default: 129 return false; 130 } 131 132 assert(CI->use_empty() && 133 "Lowering should have eliminated any uses of the intrinsic call!"); 134 CI->eraseFromParent(); 135 136 return true; 137 } 138 139 struct LowerAtomic : public BasicBlockPass { 140 static char ID; 141 LowerAtomic() : BasicBlockPass(ID) {} 142 bool runOnBasicBlock(BasicBlock &BB) { 143 bool Changed = false; 144 for (BasicBlock::iterator DI = BB.begin(), DE = BB.end(); DI != DE; ) { 145 Instruction *Inst = DI++; 146 if (CallInst *CI = dyn_cast<CallInst>(Inst)) 147 Changed |= LowerAtomicIntrinsic(CI); 148 } 149 return Changed; 150 } 151 152 }; 153 154 } 155 156 char LowerAtomic::ID = 0; 157 INITIALIZE_PASS(LowerAtomic, "loweratomic", 158 "Lower atomic intrinsics to non-atomic form", 159 false, false); 160 161 Pass *llvm::createLowerAtomicPass() { return new LowerAtomic(); } 162