diff options
author | Peter Collingbourne <peter@pcc.me.uk> | 2010-08-03 16:19:16 +0000 |
---|---|---|
committer | Peter Collingbourne <peter@pcc.me.uk> | 2010-08-03 16:19:16 +0000 |
commit | 3bababf880bfeaf1bcda7e4f808007621b6bfac8 (patch) | |
tree | b196a4e4cd842b2ce6feb36357edbdc4adfdf9aa /lib | |
parent | 795e70e4319bb38eb92701c2a463eeb7584a9b25 (diff) | |
download | llvm-3bababf880bfeaf1bcda7e4f808007621b6bfac8.tar.gz llvm-3bababf880bfeaf1bcda7e4f808007621b6bfac8.tar.bz2 llvm-3bababf880bfeaf1bcda7e4f808007621b6bfac8.tar.xz |
Add an atomic lowering pass
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@110113 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Transforms/Scalar/CMakeLists.txt | 1 | ||||
-rw-r--r-- | lib/Transforms/Scalar/LowerAtomic.cpp | 160 |
2 files changed, 161 insertions, 0 deletions
diff --git a/lib/Transforms/Scalar/CMakeLists.txt b/lib/Transforms/Scalar/CMakeLists.txt index 1a3b10cc9b..c8028c2470 100644 --- a/lib/Transforms/Scalar/CMakeLists.txt +++ b/lib/Transforms/Scalar/CMakeLists.txt @@ -17,6 +17,7 @@ add_llvm_library(LLVMScalarOpts LoopStrengthReduce.cpp LoopUnrollPass.cpp LoopUnswitch.cpp + LowerAtomic.cpp MemCpyOptimizer.cpp Reassociate.cpp Reg2Mem.cpp diff --git a/lib/Transforms/Scalar/LowerAtomic.cpp b/lib/Transforms/Scalar/LowerAtomic.cpp new file mode 100644 index 0000000000..11f52570e1 --- /dev/null +++ b/lib/Transforms/Scalar/LowerAtomic.cpp @@ -0,0 +1,160 @@ +//===- LowerAtomic.cpp - Lower atomic intrinsics --------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This pass lowers atomic intrinsics to non-atomic form for use in a known +// non-preemptible environment. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "loweratomic" +#include "llvm/Transforms/Scalar.h" +#include "llvm/BasicBlock.h" +#include "llvm/Function.h" +#include "llvm/Instruction.h" +#include "llvm/Instructions.h" +#include "llvm/Intrinsics.h" +#include "llvm/Pass.h" +#include "llvm/Support/IRBuilder.h" + +using namespace llvm; + +namespace { + +bool LowerAtomicIntrinsic(CallInst *CI) { + IRBuilder<> Builder(CI->getParent(), CI); + + Function *Callee = CI->getCalledFunction(); + if (!Callee) + return false; + + unsigned IID = Callee->getIntrinsicID(); + switch (IID) { + case Intrinsic::memory_barrier: + break; + + case Intrinsic::atomic_load_add: + case Intrinsic::atomic_load_sub: + case Intrinsic::atomic_load_and: + case Intrinsic::atomic_load_nand: + case Intrinsic::atomic_load_or: + case Intrinsic::atomic_load_xor: + case Intrinsic::atomic_load_max: + case Intrinsic::atomic_load_min: + case Intrinsic::atomic_load_umax: + case Intrinsic::atomic_load_umin: { + Value *Ptr = CI->getArgOperand(0); + Value *Delta = CI->getArgOperand(1); + + LoadInst *Orig = Builder.CreateLoad(Ptr); + Value *Res; + switch (IID) { + case Intrinsic::atomic_load_add: + Res = Builder.CreateAdd(Orig, Delta); + break; + case Intrinsic::atomic_load_sub: + Res = Builder.CreateSub(Orig, Delta); + break; + case Intrinsic::atomic_load_and: + Res = Builder.CreateAnd(Orig, Delta); + break; + case Intrinsic::atomic_load_nand: + Res = Builder.CreateNot(Builder.CreateAnd(Orig, Delta)); + break; + case Intrinsic::atomic_load_or: + Res = Builder.CreateOr(Orig, Delta); + break; + case Intrinsic::atomic_load_xor: + Res = Builder.CreateXor(Orig, Delta); + break; + case Intrinsic::atomic_load_max: + Res = Builder.CreateSelect(Builder.CreateICmpSLT(Orig, Delta), + Delta, + Orig); + break; + case Intrinsic::atomic_load_min: + Res = Builder.CreateSelect(Builder.CreateICmpSLT(Orig, Delta), + Orig, + Delta); + break; + case Intrinsic::atomic_load_umax: + Res = Builder.CreateSelect(Builder.CreateICmpULT(Orig, Delta), + Delta, + Orig); + break; + case Intrinsic::atomic_load_umin: + Res = Builder.CreateSelect(Builder.CreateICmpULT(Orig, Delta), + Orig, + Delta); + break; + default: assert(0 && "Unrecognized atomic modify operation"); + } + Builder.CreateStore(Res, Ptr); + + CI->replaceAllUsesWith(Orig); + break; + } + + case Intrinsic::atomic_swap: { + Value *Ptr = CI->getArgOperand(0); + Value *Val = CI->getArgOperand(1); + + LoadInst *Orig = Builder.CreateLoad(Ptr); + Builder.CreateStore(Val, Ptr); + + CI->replaceAllUsesWith(Orig); + break; + } + + case Intrinsic::atomic_cmp_swap: { + Value *Ptr = CI->getArgOperand(0); + Value *Cmp = CI->getArgOperand(1); + Value *Val = CI->getArgOperand(2); + + LoadInst *Orig = Builder.CreateLoad(Ptr); + Value *Equal = Builder.CreateICmpEQ(Orig, Cmp); + Value *Res = Builder.CreateSelect(Equal, Val, Orig); + Builder.CreateStore(Res, Ptr); + + CI->replaceAllUsesWith(Orig); + break; + } + + default: + return false; + } + + assert(CI->use_empty() && + "Lowering should have eliminated any uses of the intrinsic call!"); + CI->eraseFromParent(); + + return true; +} + +struct LowerAtomic : public BasicBlockPass { + static char ID; + LowerAtomic() : BasicBlockPass(&ID) {} + bool runOnBasicBlock(BasicBlock &BB) { + bool Changed = false; + for (BasicBlock::iterator DI = BB.begin(), DE = BB.end(); DI != DE; ) { + Instruction *Inst = DI++; + if (CallInst *CI = dyn_cast<CallInst>(Inst)) + Changed |= LowerAtomicIntrinsic(CI); + } + return Changed; + } + +}; + +} + +char LowerAtomic::ID = 0; +static RegisterPass<LowerAtomic> +X("loweratomic", "Lower atomic intrinsics to non-atomic form"); + +Pass *llvm::createLowerAtomicPass() { return new LowerAtomic(); } |