LowerAtomic.cpp 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. //===- LowerAtomic.cpp - Lower atomic intrinsics --------------------------===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. //
  9. // This pass lowers atomic intrinsics to non-atomic form for use in a known
  10. // non-preemptible environment.
  11. //
  12. //===----------------------------------------------------------------------===//
  13. #include "llvm/Transforms/Scalar/LowerAtomic.h"
  14. #include "llvm/IR/Function.h"
  15. #include "llvm/IR/IRBuilder.h"
  16. #include "llvm/InitializePasses.h"
  17. #include "llvm/Pass.h"
  18. #include "llvm/Transforms/Scalar.h"
  19. using namespace llvm;
  20. #define DEBUG_TYPE "loweratomic"
  21. static bool LowerAtomicCmpXchgInst(AtomicCmpXchgInst *CXI) {
  22. IRBuilder<> Builder(CXI);
  23. Value *Ptr = CXI->getPointerOperand();
  24. Value *Cmp = CXI->getCompareOperand();
  25. Value *Val = CXI->getNewValOperand();
  26. LoadInst *Orig = Builder.CreateLoad(Val->getType(), Ptr);
  27. Value *Equal = Builder.CreateICmpEQ(Orig, Cmp);
  28. Value *Res = Builder.CreateSelect(Equal, Val, Orig);
  29. Builder.CreateStore(Res, Ptr);
  30. Res = Builder.CreateInsertValue(UndefValue::get(CXI->getType()), Orig, 0);
  31. Res = Builder.CreateInsertValue(Res, Equal, 1);
  32. CXI->replaceAllUsesWith(Res);
  33. CXI->eraseFromParent();
  34. return true;
  35. }
  36. bool llvm::lowerAtomicRMWInst(AtomicRMWInst *RMWI) {
  37. IRBuilder<> Builder(RMWI);
  38. Value *Ptr = RMWI->getPointerOperand();
  39. Value *Val = RMWI->getValOperand();
  40. LoadInst *Orig = Builder.CreateLoad(Val->getType(), Ptr);
  41. Value *Res = nullptr;
  42. switch (RMWI->getOperation()) {
  43. default: llvm_unreachable("Unexpected RMW operation");
  44. case AtomicRMWInst::Xchg:
  45. Res = Val;
  46. break;
  47. case AtomicRMWInst::Add:
  48. Res = Builder.CreateAdd(Orig, Val);
  49. break;
  50. case AtomicRMWInst::Sub:
  51. Res = Builder.CreateSub(Orig, Val);
  52. break;
  53. case AtomicRMWInst::And:
  54. Res = Builder.CreateAnd(Orig, Val);
  55. break;
  56. case AtomicRMWInst::Nand:
  57. Res = Builder.CreateNot(Builder.CreateAnd(Orig, Val));
  58. break;
  59. case AtomicRMWInst::Or:
  60. Res = Builder.CreateOr(Orig, Val);
  61. break;
  62. case AtomicRMWInst::Xor:
  63. Res = Builder.CreateXor(Orig, Val);
  64. break;
  65. case AtomicRMWInst::Max:
  66. Res = Builder.CreateSelect(Builder.CreateICmpSLT(Orig, Val),
  67. Val, Orig);
  68. break;
  69. case AtomicRMWInst::Min:
  70. Res = Builder.CreateSelect(Builder.CreateICmpSLT(Orig, Val),
  71. Orig, Val);
  72. break;
  73. case AtomicRMWInst::UMax:
  74. Res = Builder.CreateSelect(Builder.CreateICmpULT(Orig, Val),
  75. Val, Orig);
  76. break;
  77. case AtomicRMWInst::UMin:
  78. Res = Builder.CreateSelect(Builder.CreateICmpULT(Orig, Val),
  79. Orig, Val);
  80. break;
  81. case AtomicRMWInst::FAdd:
  82. Res = Builder.CreateFAdd(Orig, Val);
  83. break;
  84. case AtomicRMWInst::FSub:
  85. Res = Builder.CreateFSub(Orig, Val);
  86. break;
  87. }
  88. Builder.CreateStore(Res, Ptr);
  89. RMWI->replaceAllUsesWith(Orig);
  90. RMWI->eraseFromParent();
  91. return true;
  92. }
  93. static bool LowerFenceInst(FenceInst *FI) {
  94. FI->eraseFromParent();
  95. return true;
  96. }
  97. static bool LowerLoadInst(LoadInst *LI) {
  98. LI->setAtomic(AtomicOrdering::NotAtomic);
  99. return true;
  100. }
  101. static bool LowerStoreInst(StoreInst *SI) {
  102. SI->setAtomic(AtomicOrdering::NotAtomic);
  103. return true;
  104. }
  105. static bool runOnBasicBlock(BasicBlock &BB) {
  106. bool Changed = false;
  107. for (Instruction &Inst : make_early_inc_range(BB)) {
  108. if (FenceInst *FI = dyn_cast<FenceInst>(&Inst))
  109. Changed |= LowerFenceInst(FI);
  110. else if (AtomicCmpXchgInst *CXI = dyn_cast<AtomicCmpXchgInst>(&Inst))
  111. Changed |= LowerAtomicCmpXchgInst(CXI);
  112. else if (AtomicRMWInst *RMWI = dyn_cast<AtomicRMWInst>(&Inst))
  113. Changed |= lowerAtomicRMWInst(RMWI);
  114. else if (LoadInst *LI = dyn_cast<LoadInst>(&Inst)) {
  115. if (LI->isAtomic())
  116. LowerLoadInst(LI);
  117. } else if (StoreInst *SI = dyn_cast<StoreInst>(&Inst)) {
  118. if (SI->isAtomic())
  119. LowerStoreInst(SI);
  120. }
  121. }
  122. return Changed;
  123. }
  124. static bool lowerAtomics(Function &F) {
  125. bool Changed = false;
  126. for (BasicBlock &BB : F) {
  127. Changed |= runOnBasicBlock(BB);
  128. }
  129. return Changed;
  130. }
  131. PreservedAnalyses LowerAtomicPass::run(Function &F, FunctionAnalysisManager &) {
  132. if (lowerAtomics(F))
  133. return PreservedAnalyses::none();
  134. return PreservedAnalyses::all();
  135. }
  136. namespace {
  137. class LowerAtomicLegacyPass : public FunctionPass {
  138. public:
  139. static char ID;
  140. LowerAtomicLegacyPass() : FunctionPass(ID) {
  141. initializeLowerAtomicLegacyPassPass(*PassRegistry::getPassRegistry());
  142. }
  143. bool runOnFunction(Function &F) override {
  144. // Don't skip optnone functions; atomics still need to be lowered.
  145. FunctionAnalysisManager DummyFAM;
  146. auto PA = Impl.run(F, DummyFAM);
  147. return !PA.areAllPreserved();
  148. }
  149. private:
  150. LowerAtomicPass Impl;
  151. };
  152. }
  153. char LowerAtomicLegacyPass::ID = 0;
  154. INITIALIZE_PASS(LowerAtomicLegacyPass, "loweratomic",
  155. "Lower atomic intrinsics to non-atomic form", false, false)
  156. Pass *llvm::createLowerAtomicPass() { return new LowerAtomicLegacyPass(); }