xref: /freebsd-src/contrib/llvm-project/llvm/lib/Transforms/Utils/LowerAtomic.cpp (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
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