181ad6265SDimitry Andric //===- LowerAtomic.cpp - Lower atomic intrinsics --------------------------===// 281ad6265SDimitry Andric // 381ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 481ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 581ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 681ad6265SDimitry Andric // 781ad6265SDimitry Andric //===----------------------------------------------------------------------===// 881ad6265SDimitry Andric // 981ad6265SDimitry Andric // This pass lowers atomic intrinsics to non-atomic form for use in a known 1081ad6265SDimitry Andric // non-preemptible environment. 1181ad6265SDimitry Andric // 1281ad6265SDimitry Andric //===----------------------------------------------------------------------===// 1381ad6265SDimitry Andric 1481ad6265SDimitry Andric #include "llvm/Transforms/Utils/LowerAtomic.h" 1581ad6265SDimitry Andric #include "llvm/IR/Function.h" 1681ad6265SDimitry Andric #include "llvm/IR/IRBuilder.h" 1781ad6265SDimitry Andric #include "llvm/InitializePasses.h" 1881ad6265SDimitry Andric #include "llvm/Pass.h" 1981ad6265SDimitry Andric using namespace llvm; 2081ad6265SDimitry Andric 2181ad6265SDimitry Andric #define DEBUG_TYPE "loweratomic" 2281ad6265SDimitry Andric 2381ad6265SDimitry Andric bool llvm::lowerAtomicCmpXchgInst(AtomicCmpXchgInst *CXI) { 2481ad6265SDimitry Andric IRBuilder<> Builder(CXI); 2581ad6265SDimitry Andric Value *Ptr = CXI->getPointerOperand(); 2681ad6265SDimitry Andric Value *Cmp = CXI->getCompareOperand(); 2781ad6265SDimitry Andric Value *Val = CXI->getNewValOperand(); 2881ad6265SDimitry Andric 2981ad6265SDimitry Andric LoadInst *Orig = Builder.CreateLoad(Val->getType(), Ptr); 3081ad6265SDimitry Andric Value *Equal = Builder.CreateICmpEQ(Orig, Cmp); 3181ad6265SDimitry Andric Value *Res = Builder.CreateSelect(Equal, Val, Orig); 3281ad6265SDimitry Andric Builder.CreateStore(Res, Ptr); 3381ad6265SDimitry Andric 34fcaf7f86SDimitry Andric Res = Builder.CreateInsertValue(PoisonValue::get(CXI->getType()), Orig, 0); 3581ad6265SDimitry Andric Res = Builder.CreateInsertValue(Res, Equal, 1); 3681ad6265SDimitry Andric 3781ad6265SDimitry Andric CXI->replaceAllUsesWith(Res); 3881ad6265SDimitry Andric CXI->eraseFromParent(); 3981ad6265SDimitry Andric return true; 4081ad6265SDimitry Andric } 4181ad6265SDimitry Andric 4281ad6265SDimitry Andric Value *llvm::buildAtomicRMWValue(AtomicRMWInst::BinOp Op, 4381ad6265SDimitry Andric IRBuilderBase &Builder, Value *Loaded, 44*bdd1243dSDimitry Andric Value *Val) { 4581ad6265SDimitry Andric Value *NewVal; 4681ad6265SDimitry Andric switch (Op) { 4781ad6265SDimitry Andric case AtomicRMWInst::Xchg: 48*bdd1243dSDimitry Andric return Val; 4981ad6265SDimitry Andric case AtomicRMWInst::Add: 50*bdd1243dSDimitry Andric return Builder.CreateAdd(Loaded, Val, "new"); 5181ad6265SDimitry Andric case AtomicRMWInst::Sub: 52*bdd1243dSDimitry Andric return Builder.CreateSub(Loaded, Val, "new"); 5381ad6265SDimitry Andric case AtomicRMWInst::And: 54*bdd1243dSDimitry Andric return Builder.CreateAnd(Loaded, Val, "new"); 5581ad6265SDimitry Andric case AtomicRMWInst::Nand: 56*bdd1243dSDimitry Andric return Builder.CreateNot(Builder.CreateAnd(Loaded, Val), "new"); 5781ad6265SDimitry Andric case AtomicRMWInst::Or: 58*bdd1243dSDimitry Andric return Builder.CreateOr(Loaded, Val, "new"); 5981ad6265SDimitry Andric case AtomicRMWInst::Xor: 60*bdd1243dSDimitry Andric return Builder.CreateXor(Loaded, Val, "new"); 6181ad6265SDimitry Andric case AtomicRMWInst::Max: 62*bdd1243dSDimitry Andric NewVal = Builder.CreateICmpSGT(Loaded, Val); 63*bdd1243dSDimitry Andric return Builder.CreateSelect(NewVal, Loaded, Val, "new"); 6481ad6265SDimitry Andric case AtomicRMWInst::Min: 65*bdd1243dSDimitry Andric NewVal = Builder.CreateICmpSLE(Loaded, Val); 66*bdd1243dSDimitry Andric return Builder.CreateSelect(NewVal, Loaded, Val, "new"); 6781ad6265SDimitry Andric case AtomicRMWInst::UMax: 68*bdd1243dSDimitry Andric NewVal = Builder.CreateICmpUGT(Loaded, Val); 69*bdd1243dSDimitry Andric return Builder.CreateSelect(NewVal, Loaded, Val, "new"); 7081ad6265SDimitry Andric case AtomicRMWInst::UMin: 71*bdd1243dSDimitry Andric NewVal = Builder.CreateICmpULE(Loaded, Val); 72*bdd1243dSDimitry Andric return Builder.CreateSelect(NewVal, Loaded, Val, "new"); 7381ad6265SDimitry Andric case AtomicRMWInst::FAdd: 74*bdd1243dSDimitry Andric return Builder.CreateFAdd(Loaded, Val, "new"); 7581ad6265SDimitry Andric case AtomicRMWInst::FSub: 76*bdd1243dSDimitry Andric return Builder.CreateFSub(Loaded, Val, "new"); 77753f127fSDimitry Andric case AtomicRMWInst::FMax: 78*bdd1243dSDimitry Andric return Builder.CreateMaxNum(Loaded, Val); 79753f127fSDimitry Andric case AtomicRMWInst::FMin: 80*bdd1243dSDimitry Andric return Builder.CreateMinNum(Loaded, Val); 81*bdd1243dSDimitry Andric case AtomicRMWInst::UIncWrap: { 82*bdd1243dSDimitry Andric Constant *One = ConstantInt::get(Loaded->getType(), 1); 83*bdd1243dSDimitry Andric Value *Inc = Builder.CreateAdd(Loaded, One); 84*bdd1243dSDimitry Andric Value *Cmp = Builder.CreateICmpUGE(Loaded, Val); 85*bdd1243dSDimitry Andric Constant *Zero = ConstantInt::get(Loaded->getType(), 0); 86*bdd1243dSDimitry Andric return Builder.CreateSelect(Cmp, Zero, Inc, "new"); 87*bdd1243dSDimitry Andric } 88*bdd1243dSDimitry Andric case AtomicRMWInst::UDecWrap: { 89*bdd1243dSDimitry Andric Constant *Zero = ConstantInt::get(Loaded->getType(), 0); 90*bdd1243dSDimitry Andric Constant *One = ConstantInt::get(Loaded->getType(), 1); 91*bdd1243dSDimitry Andric 92*bdd1243dSDimitry Andric Value *Dec = Builder.CreateSub(Loaded, One); 93*bdd1243dSDimitry Andric Value *CmpEq0 = Builder.CreateICmpEQ(Loaded, Zero); 94*bdd1243dSDimitry Andric Value *CmpOldGtVal = Builder.CreateICmpUGT(Loaded, Val); 95*bdd1243dSDimitry Andric Value *Or = Builder.CreateOr(CmpEq0, CmpOldGtVal); 96*bdd1243dSDimitry Andric return Builder.CreateSelect(Or, Val, Dec, "new"); 97*bdd1243dSDimitry Andric } 9881ad6265SDimitry Andric default: 9981ad6265SDimitry Andric llvm_unreachable("Unknown atomic op"); 10081ad6265SDimitry Andric } 10181ad6265SDimitry Andric } 10281ad6265SDimitry Andric 10381ad6265SDimitry Andric bool llvm::lowerAtomicRMWInst(AtomicRMWInst *RMWI) { 10481ad6265SDimitry Andric IRBuilder<> Builder(RMWI); 10581ad6265SDimitry Andric Value *Ptr = RMWI->getPointerOperand(); 10681ad6265SDimitry Andric Value *Val = RMWI->getValOperand(); 10781ad6265SDimitry Andric 10881ad6265SDimitry Andric LoadInst *Orig = Builder.CreateLoad(Val->getType(), Ptr); 10981ad6265SDimitry Andric Value *Res = buildAtomicRMWValue(RMWI->getOperation(), Builder, Orig, Val); 11081ad6265SDimitry Andric Builder.CreateStore(Res, Ptr); 11181ad6265SDimitry Andric RMWI->replaceAllUsesWith(Orig); 11281ad6265SDimitry Andric RMWI->eraseFromParent(); 11381ad6265SDimitry Andric return true; 11481ad6265SDimitry Andric } 115