1*81ad6265SDimitry Andric //===- LowerAtomic.cpp - Lower atomic intrinsics --------------------------===// 2*81ad6265SDimitry Andric // 3*81ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*81ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*81ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*81ad6265SDimitry Andric // 7*81ad6265SDimitry Andric //===----------------------------------------------------------------------===// 8*81ad6265SDimitry Andric // 9*81ad6265SDimitry Andric // This pass lowers atomic intrinsics to non-atomic form for use in a known 10*81ad6265SDimitry Andric // non-preemptible environment. 11*81ad6265SDimitry Andric // 12*81ad6265SDimitry Andric //===----------------------------------------------------------------------===// 13*81ad6265SDimitry Andric 14*81ad6265SDimitry Andric #include "llvm/Transforms/Utils/LowerAtomic.h" 15*81ad6265SDimitry Andric #include "llvm/IR/Function.h" 16*81ad6265SDimitry Andric #include "llvm/IR/IRBuilder.h" 17*81ad6265SDimitry Andric #include "llvm/InitializePasses.h" 18*81ad6265SDimitry Andric #include "llvm/Pass.h" 19*81ad6265SDimitry Andric using namespace llvm; 20*81ad6265SDimitry Andric 21*81ad6265SDimitry Andric #define DEBUG_TYPE "loweratomic" 22*81ad6265SDimitry Andric 23*81ad6265SDimitry Andric bool llvm::lowerAtomicCmpXchgInst(AtomicCmpXchgInst *CXI) { 24*81ad6265SDimitry Andric IRBuilder<> Builder(CXI); 25*81ad6265SDimitry Andric Value *Ptr = CXI->getPointerOperand(); 26*81ad6265SDimitry Andric Value *Cmp = CXI->getCompareOperand(); 27*81ad6265SDimitry Andric Value *Val = CXI->getNewValOperand(); 28*81ad6265SDimitry Andric 29*81ad6265SDimitry Andric LoadInst *Orig = Builder.CreateLoad(Val->getType(), Ptr); 30*81ad6265SDimitry Andric Value *Equal = Builder.CreateICmpEQ(Orig, Cmp); 31*81ad6265SDimitry Andric Value *Res = Builder.CreateSelect(Equal, Val, Orig); 32*81ad6265SDimitry Andric Builder.CreateStore(Res, Ptr); 33*81ad6265SDimitry Andric 34*81ad6265SDimitry Andric Res = Builder.CreateInsertValue(UndefValue::get(CXI->getType()), Orig, 0); 35*81ad6265SDimitry Andric Res = Builder.CreateInsertValue(Res, Equal, 1); 36*81ad6265SDimitry Andric 37*81ad6265SDimitry Andric CXI->replaceAllUsesWith(Res); 38*81ad6265SDimitry Andric CXI->eraseFromParent(); 39*81ad6265SDimitry Andric return true; 40*81ad6265SDimitry Andric } 41*81ad6265SDimitry Andric 42*81ad6265SDimitry Andric Value *llvm::buildAtomicRMWValue(AtomicRMWInst::BinOp Op, 43*81ad6265SDimitry Andric IRBuilderBase &Builder, Value *Loaded, 44*81ad6265SDimitry Andric Value *Inc) { 45*81ad6265SDimitry Andric Value *NewVal; 46*81ad6265SDimitry Andric switch (Op) { 47*81ad6265SDimitry Andric case AtomicRMWInst::Xchg: 48*81ad6265SDimitry Andric return Inc; 49*81ad6265SDimitry Andric case AtomicRMWInst::Add: 50*81ad6265SDimitry Andric return Builder.CreateAdd(Loaded, Inc, "new"); 51*81ad6265SDimitry Andric case AtomicRMWInst::Sub: 52*81ad6265SDimitry Andric return Builder.CreateSub(Loaded, Inc, "new"); 53*81ad6265SDimitry Andric case AtomicRMWInst::And: 54*81ad6265SDimitry Andric return Builder.CreateAnd(Loaded, Inc, "new"); 55*81ad6265SDimitry Andric case AtomicRMWInst::Nand: 56*81ad6265SDimitry Andric return Builder.CreateNot(Builder.CreateAnd(Loaded, Inc), "new"); 57*81ad6265SDimitry Andric case AtomicRMWInst::Or: 58*81ad6265SDimitry Andric return Builder.CreateOr(Loaded, Inc, "new"); 59*81ad6265SDimitry Andric case AtomicRMWInst::Xor: 60*81ad6265SDimitry Andric return Builder.CreateXor(Loaded, Inc, "new"); 61*81ad6265SDimitry Andric case AtomicRMWInst::Max: 62*81ad6265SDimitry Andric NewVal = Builder.CreateICmpSGT(Loaded, Inc); 63*81ad6265SDimitry Andric return Builder.CreateSelect(NewVal, Loaded, Inc, "new"); 64*81ad6265SDimitry Andric case AtomicRMWInst::Min: 65*81ad6265SDimitry Andric NewVal = Builder.CreateICmpSLE(Loaded, Inc); 66*81ad6265SDimitry Andric return Builder.CreateSelect(NewVal, Loaded, Inc, "new"); 67*81ad6265SDimitry Andric case AtomicRMWInst::UMax: 68*81ad6265SDimitry Andric NewVal = Builder.CreateICmpUGT(Loaded, Inc); 69*81ad6265SDimitry Andric return Builder.CreateSelect(NewVal, Loaded, Inc, "new"); 70*81ad6265SDimitry Andric case AtomicRMWInst::UMin: 71*81ad6265SDimitry Andric NewVal = Builder.CreateICmpULE(Loaded, Inc); 72*81ad6265SDimitry Andric return Builder.CreateSelect(NewVal, Loaded, Inc, "new"); 73*81ad6265SDimitry Andric case AtomicRMWInst::FAdd: 74*81ad6265SDimitry Andric return Builder.CreateFAdd(Loaded, Inc, "new"); 75*81ad6265SDimitry Andric case AtomicRMWInst::FSub: 76*81ad6265SDimitry Andric return Builder.CreateFSub(Loaded, Inc, "new"); 77*81ad6265SDimitry Andric default: 78*81ad6265SDimitry Andric llvm_unreachable("Unknown atomic op"); 79*81ad6265SDimitry Andric } 80*81ad6265SDimitry Andric } 81*81ad6265SDimitry Andric 82*81ad6265SDimitry Andric bool llvm::lowerAtomicRMWInst(AtomicRMWInst *RMWI) { 83*81ad6265SDimitry Andric IRBuilder<> Builder(RMWI); 84*81ad6265SDimitry Andric Value *Ptr = RMWI->getPointerOperand(); 85*81ad6265SDimitry Andric Value *Val = RMWI->getValOperand(); 86*81ad6265SDimitry Andric 87*81ad6265SDimitry Andric LoadInst *Orig = Builder.CreateLoad(Val->getType(), Ptr); 88*81ad6265SDimitry Andric Value *Res = buildAtomicRMWValue(RMWI->getOperation(), Builder, Orig, Val); 89*81ad6265SDimitry Andric Builder.CreateStore(Res, Ptr); 90*81ad6265SDimitry Andric RMWI->replaceAllUsesWith(Orig); 91*81ad6265SDimitry Andric RMWI->eraseFromParent(); 92*81ad6265SDimitry Andric return true; 93*81ad6265SDimitry Andric } 94