LLVM 24.0.0git
LowerAtomic.cpp
Go to the documentation of this file.
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
15#include "llvm/IR/Function.h"
16#include "llvm/IR/IRBuilder.h"
17
18using namespace llvm;
19
20#define DEBUG_TYPE "loweratomic"
21
23 IRBuilder<> Builder(CXI);
24 Value *Ptr = CXI->getPointerOperand();
25 Value *Cmp = CXI->getCompareOperand();
26 Value *Val = CXI->getNewValOperand();
27
28 auto [Orig, Equal] = buildCmpXchgValue(Builder, Ptr, Cmp, Val,
29 CXI->getAlign(), CXI->isVolatile());
30
31 Value *Res =
32 Builder.CreateInsertValue(PoisonValue::get(CXI->getType()), Orig, 0);
33 Res = Builder.CreateInsertValue(Res, Equal, 1);
34
35 CXI->replaceAllUsesWith(Res);
36 CXI->eraseFromParent();
37 return true;
38}
39
40std::pair<Value *, Value *> llvm::buildCmpXchgValue(IRBuilderBase &Builder,
41 Value *Ptr, Value *Cmp,
42 Value *Val, Align Alignment,
43 bool IsVolatile) {
44 LoadInst *Orig =
45 Builder.CreateAlignedLoad(Val->getType(), Ptr, Alignment, IsVolatile);
46 Value *Equal = Builder.CreateICmpEQ(Orig, Cmp);
47 // We have no idea what the probability of the value in memory being equal to
48 // the comparison value is without additional VP metadata, so explicitly mark
49 // it unknown.
50 Value *Res =
51 Builder.CreateSelectWithUnknownProfile(Equal, Val, Orig, DEBUG_TYPE);
52 Builder.CreateAlignedStore(Res, Ptr, Alignment, IsVolatile);
53
54 return {Orig, Equal};
55}
56
58 IRBuilderBase &Builder, Value *Loaded,
59 Value *Val) {
60 Value *NewVal;
61 switch (Op) {
63 return Val;
65 return Builder.CreateAdd(Loaded, Val, "new");
67 return Builder.CreateSub(Loaded, Val, "new");
69 return Builder.CreateAnd(Loaded, Val, "new");
71 return Builder.CreateNot(Builder.CreateAnd(Loaded, Val), "new");
73 return Builder.CreateOr(Loaded, Val, "new");
75 return Builder.CreateXor(Loaded, Val, "new");
77 NewVal = Builder.CreateICmpSGT(Loaded, Val);
78 return Builder.CreateSelect(NewVal, Loaded, Val, "new");
80 NewVal = Builder.CreateICmpSLE(Loaded, Val);
81 return Builder.CreateSelect(NewVal, Loaded, Val, "new");
83 NewVal = Builder.CreateICmpUGT(Loaded, Val);
84 return Builder.CreateSelect(NewVal, Loaded, Val, "new");
86 NewVal = Builder.CreateICmpULE(Loaded, Val);
87 return Builder.CreateSelect(NewVal, Loaded, Val, "new");
89 return Builder.CreateFAdd(Loaded, Val, "new");
91 return Builder.CreateFSub(Loaded, Val, "new");
93 return Builder.CreateMaxNum(Loaded, Val);
95 return Builder.CreateMinNum(Loaded, Val);
97 return Builder.CreateMaximum(Loaded, Val);
99 return Builder.CreateMinimum(Loaded, Val);
101 return Builder.CreateMaximumNum(Loaded, Val);
103 return Builder.CreateMinimumNum(Loaded, Val);
105 Constant *One = ConstantInt::get(Loaded->getType(), 1);
106 Value *Inc = Builder.CreateAdd(Loaded, One);
107 Value *Cmp = Builder.CreateICmpUGE(Loaded, Val);
108 Constant *Zero = ConstantInt::get(Loaded->getType(), 0);
109 return Builder.CreateSelect(Cmp, Zero, Inc, "new");
110 }
112 Constant *Zero = ConstantInt::get(Loaded->getType(), 0);
113 Constant *One = ConstantInt::get(Loaded->getType(), 1);
114
115 Value *Dec = Builder.CreateSub(Loaded, One);
116 Value *CmpEq0 = Builder.CreateICmpEQ(Loaded, Zero);
117 Value *CmpOldGtVal = Builder.CreateICmpUGT(Loaded, Val);
118 Value *Or = Builder.CreateOr(CmpEq0, CmpOldGtVal);
119 return Builder.CreateSelect(Or, Val, Dec, "new");
120 }
122 Value *Cmp = Builder.CreateICmpUGE(Loaded, Val);
123 Value *Sub = Builder.CreateSub(Loaded, Val);
124 return Builder.CreateSelect(Cmp, Sub, Loaded, "new");
125 }
127 return Builder.CreateIntrinsic(Intrinsic::usub_sat, Loaded->getType(),
128 {Loaded, Val}, nullptr, "new");
129 default:
130 llvm_unreachable("Unknown atomic op");
131 }
132}
133
135 IRBuilder<> Builder(RMWI);
136 Builder.setIsFPConstrained(
137 RMWI->getFunction()->hasFnAttribute(Attribute::StrictFP));
138
139 Value *Ptr = RMWI->getPointerOperand();
140 Value *Val = RMWI->getValOperand();
141
142 LoadInst *Orig = Builder.CreateLoad(Val->getType(), Ptr, RMWI->isVolatile());
143 Value *Res = buildAtomicRMWValue(RMWI->getOperation(), Builder, Orig, Val);
144 Builder.CreateStore(Res, Ptr)->setVolatile(RMWI->isVolatile());
145 RMWI->replaceAllUsesWith(Orig);
146 RMWI->eraseFromParent();
147 return true;
148}
#define DEBUG_TYPE
An instruction that atomically checks whether a specified value is in a memory location,...
bool isVolatile() const
Return true if this is a cmpxchg from a volatile memory location.
Align getAlign() const
Return the alignment of the memory that is being allocated by the instruction.
an instruction that atomically reads a memory location, combines it with another value,...
bool isVolatile() const
Return true if this is a RMW on a volatile memory location.
BinOp
This enumeration lists the possible modifications atomicrmw can make.
@ Add
*p = old + v
@ FAdd
*p = old + v
@ USubCond
Subtract only if no unsigned overflow.
@ FMinimum
*p = minimum(old, v) minimum matches the behavior of llvm.minimum.
@ Min
*p = old <signed v ? old : v
@ Sub
*p = old - v
@ And
*p = old & v
@ Xor
*p = old ^ v
@ USubSat
*p = usub.sat(old, v) usub.sat matches the behavior of llvm.usub.sat.
@ FMaximum
*p = maximum(old, v) maximum matches the behavior of llvm.maximum.
@ FSub
*p = old - v
@ UIncWrap
Increment one up to a maximum value.
@ Max
*p = old >signed v ? old : v
@ UMin
*p = old <unsigned v ? old : v
@ FMin
*p = minnum(old, v) minnum matches the behavior of llvm.minnum.
@ UMax
*p = old >unsigned v ? old : v
@ FMaximumNum
*p = maximumnum(old, v) maximumnum matches the behavior of llvm.maximumnum.
@ FMax
*p = maxnum(old, v) maxnum matches the behavior of llvm.maxnum.
@ UDecWrap
Decrement one until a minimum value or zero.
@ FMinimumNum
*p = minimumnum(old, v) minimumnum matches the behavior of llvm.minimumnum.
@ Nand
*p = ~(old & v)
Value * getPointerOperand()
BinOp getOperation() const
This is an important base class in LLVM.
Definition Constant.h:43
bool hasFnAttribute(Attribute::AttrKind Kind) const
Return true if the function has the attribute.
Definition Function.cpp:730
Common base class shared among various IRBuilders.
Definition IRBuilder.h:114
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
Definition IRBuilder.h:2908
LLVM_ABI InstListType::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
LLVM_ABI const Function * getFunction() const
Return the function this instruction belongs to.
An instruction for reading from memory.
static LLVM_ABI PoisonValue * get(Type *T)
Static factory methods - Return an 'poison' object of the specified type.
LLVM Value Representation.
Definition Value.h:75
Type * getType() const
All values are typed, get the type of this value.
Definition Value.h:257
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
Definition Value.cpp:553
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
This is an optimization pass for GlobalISel generic memory operations.
LLVM_ABI Value * buildAtomicRMWValue(AtomicRMWInst::BinOp Op, IRBuilderBase &Builder, Value *Loaded, Value *Val)
Emit IR to implement the given atomicrmw operation on values in registers, returning the new value.
@ Sub
Subtraction of integers.
DWARFExpression::Operation Op
LLVM_ABI bool lowerAtomicCmpXchgInst(AtomicCmpXchgInst *CXI)
Convert the given Cmpxchg into primitive load and compare.
LLVM_ABI std::pair< Value *, Value * > buildCmpXchgValue(IRBuilderBase &Builder, Value *Ptr, Value *Cmp, Value *Val, Align Alignment, bool IsVolatile=false)
Emit IR to implement the given cmpxchg operation on values in registers, returning the new value.
LLVM_ABI bool lowerAtomicRMWInst(AtomicRMWInst *RMWI)
Convert the given RMWI into primitive load and stores, assuming that doing so is legal.
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition Alignment.h:39