| //===- LowerAtomic.cpp - Lower atomic intrinsics --------------------------===// | |
| // | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| // See https://llvm.org/LICENSE.txt for license information. | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| // | |
| //===----------------------------------------------------------------------===// | |
| // | |
| // This pass lowers atomic intrinsics to non-atomic form for use in a known | |
| // non-preemptible environment. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #include "llvm/Transforms/Utils/LowerAtomic.h" | |
| #include "llvm/IR/Function.h" | |
| #include "llvm/IR/IRBuilder.h" | |
| #include "llvm/InitializePasses.h" | |
| #include "llvm/Pass.h" | |
| using namespace llvm; | |
| #define DEBUG_TYPE "loweratomic" | |
| bool llvm::lowerAtomicCmpXchgInst(AtomicCmpXchgInst *CXI) { | |
| IRBuilder<> Builder(CXI); | |
| Value *Ptr = CXI->getPointerOperand(); | |
| Value *Cmp = CXI->getCompareOperand(); | |
| Value *Val = CXI->getNewValOperand(); | |
| LoadInst *Orig = Builder.CreateLoad(Val->getType(), Ptr); | |
| Value *Equal = Builder.CreateICmpEQ(Orig, Cmp); | |
| Value *Res = Builder.CreateSelect(Equal, Val, Orig); | |
| Builder.CreateStore(Res, Ptr); | |
| Res = Builder.CreateInsertValue(PoisonValue::get(CXI->getType()), Orig, 0); | |
| Res = Builder.CreateInsertValue(Res, Equal, 1); | |
| CXI->replaceAllUsesWith(Res); | |
| CXI->eraseFromParent(); | |
| return true; | |
| } | |
| Value *llvm::buildAtomicRMWValue(AtomicRMWInst::BinOp Op, | |
| IRBuilderBase &Builder, Value *Loaded, | |
| Value *Val) { | |
| Value *NewVal; | |
| switch (Op) { | |
| case AtomicRMWInst::Xchg: | |
| return Val; | |
| case AtomicRMWInst::Add: | |
| return Builder.CreateAdd(Loaded, Val, "new"); | |
| case AtomicRMWInst::Sub: | |
| return Builder.CreateSub(Loaded, Val, "new"); | |
| case AtomicRMWInst::And: | |
| return Builder.CreateAnd(Loaded, Val, "new"); | |
| case AtomicRMWInst::Nand: | |
| return Builder.CreateNot(Builder.CreateAnd(Loaded, Val), "new"); | |
| case AtomicRMWInst::Or: | |
| return Builder.CreateOr(Loaded, Val, "new"); | |
| case AtomicRMWInst::Xor: | |
| return Builder.CreateXor(Loaded, Val, "new"); | |
| case AtomicRMWInst::Max: | |
| NewVal = Builder.CreateICmpSGT(Loaded, Val); | |
| return Builder.CreateSelect(NewVal, Loaded, Val, "new"); | |
| case AtomicRMWInst::Min: | |
| NewVal = Builder.CreateICmpSLE(Loaded, Val); | |
| return Builder.CreateSelect(NewVal, Loaded, Val, "new"); | |
| case AtomicRMWInst::UMax: | |
| NewVal = Builder.CreateICmpUGT(Loaded, Val); | |
| return Builder.CreateSelect(NewVal, Loaded, Val, "new"); | |
| case AtomicRMWInst::UMin: | |
| NewVal = Builder.CreateICmpULE(Loaded, Val); | |
| return Builder.CreateSelect(NewVal, Loaded, Val, "new"); | |
| case AtomicRMWInst::FAdd: | |
| return Builder.CreateFAdd(Loaded, Val, "new"); | |
| case AtomicRMWInst::FSub: | |
| return Builder.CreateFSub(Loaded, Val, "new"); | |
| case AtomicRMWInst::FMax: | |
| return Builder.CreateMaxNum(Loaded, Val); | |
| case AtomicRMWInst::FMin: | |
| return Builder.CreateMinNum(Loaded, Val); | |
| case AtomicRMWInst::UIncWrap: { | |
| Constant *One = ConstantInt::get(Loaded->getType(), 1); | |
| Value *Inc = Builder.CreateAdd(Loaded, One); | |
| Value *Cmp = Builder.CreateICmpUGE(Loaded, Val); | |
| Constant *Zero = ConstantInt::get(Loaded->getType(), 0); | |
| return Builder.CreateSelect(Cmp, Zero, Inc, "new"); | |
| } | |
| case AtomicRMWInst::UDecWrap: { | |
| Constant *Zero = ConstantInt::get(Loaded->getType(), 0); | |
| Constant *One = ConstantInt::get(Loaded->getType(), 1); | |
| Value *Dec = Builder.CreateSub(Loaded, One); | |
| Value *CmpEq0 = Builder.CreateICmpEQ(Loaded, Zero); | |
| Value *CmpOldGtVal = Builder.CreateICmpUGT(Loaded, Val); | |
| Value *Or = Builder.CreateOr(CmpEq0, CmpOldGtVal); | |
| return Builder.CreateSelect(Or, Val, Dec, "new"); | |
| } | |
| default: | |
| llvm_unreachable("Unknown atomic op"); | |
| } | |
| } | |
| bool llvm::lowerAtomicRMWInst(AtomicRMWInst *RMWI) { | |
| IRBuilder<> Builder(RMWI); | |
| Value *Ptr = RMWI->getPointerOperand(); | |
| Value *Val = RMWI->getValOperand(); | |
| LoadInst *Orig = Builder.CreateLoad(Val->getType(), Ptr); | |
| Value *Res = buildAtomicRMWValue(RMWI->getOperation(), Builder, Orig, Val); | |
| Builder.CreateStore(Res, Ptr); | |
| RMWI->replaceAllUsesWith(Orig); | |
| RMWI->eraseFromParent(); | |
| return true; | |
| } |