LLVM 23.0.0git
Atomic.cpp
Go to the documentation of this file.
1//===--- Atomic.cpp - Codegen of atomic operations ------------------------===//
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
11#include "llvm/IR/IRBuilder.h"
12#include <utility>
13
14using namespace llvm;
15
16bool AtomicInfo::shouldCastToInt(Type *ValTy, bool CmpXchg) {
17 if (ValTy->isFloatingPointTy())
18 return ValTy->isX86_FP80Ty() || CmpXchg;
19 return !ValTy->isIntegerTy() && !ValTy->isPointerTy();
20}
21
23 bool CmpXchg) {
24 Value *Ptr = getAtomicPointer();
25 Type *AtomicTy = Ty;
26 if (shouldCastToInt(Ty, CmpXchg))
28 LoadInst *Load =
29 Builder->CreateAlignedLoad(AtomicTy, Ptr, AtomicAlign, "atomic-load");
30 Load->setAtomic(AO);
31 if (IsVolatile)
32 Load->setVolatile(true);
33 decorateWithTBAA(Load);
34 return Load;
35}
36
38 ArrayRef<Value *> Args) {
39 LLVMContext &ctx = Builder->getContext();
41 for (Value *Arg : Args)
42 ArgTys.push_back(Arg->getType());
43 FunctionType *FnType = FunctionType::get(ResultType, ArgTys, false);
44 Module *M = Builder->GetInsertBlock()->getModule();
45
46 // TODO: Use llvm::TargetLowering for Libcall ABI
47 AttrBuilder fnAttrBuilder(ctx);
48 fnAttrBuilder.addAttribute(Attribute::NoUnwind);
49 fnAttrBuilder.addAttribute(Attribute::WillReturn);
50 AttributeList fnAttrs =
51 AttributeList::get(ctx, AttributeList::FunctionIndex, fnAttrBuilder);
52 FunctionCallee LibcallFn = M->getOrInsertFunction(fnName, FnType, fnAttrs);
53 CallInst *Call = Builder->CreateCall(LibcallFn, Args);
54 return Call;
55}
56
58 Value *ExpectedVal, Value *DesiredVal, AtomicOrdering Success,
59 AtomicOrdering Failure) {
61
62 // __atomic_compare_exchange's expected and desired are passed by pointers
63 // FIXME: types
64
65 // TODO: Get from llvm::TargetMachine / clang::TargetInfo
66 // if clang shares this codegen in future
67 constexpr uint64_t IntBits = 32;
68
69 // bool __atomic_compare_exchange(size_t size, void *obj, void *expected,
70 // void *desired, int success, int failure);
71
72 Value *Args[6] = {
75 ExpectedVal,
76 DesiredVal,
78 APInt(IntBits,
79 static_cast<uint64_t>(toCABI(Success)),
80 /*signed=*/true)),
82 APInt(IntBits,
83 static_cast<uint64_t>(toCABI(Failure)),
84 /*signed=*/true)),
85 };
86 auto Result = EmitAtomicLibcall("__atomic_compare_exchange",
87 IntegerType::getInt1Ty(ctx), Args);
88 return std::make_pair(ExpectedVal, Result);
89}
90
91std::pair<Value *, Value *> AtomicInfo::EmitAtomicCompareExchangeOp(
92 Value *ExpectedVal, Value *DesiredVal, AtomicOrdering Success,
93 AtomicOrdering Failure, bool IsVolatile, bool IsWeak) {
94 // Do the atomic store.
96 auto *Inst = Builder->CreateAtomicCmpXchg(Addr, ExpectedVal, DesiredVal,
98 Failure, SyncScope::System);
99
100 // Other decoration.
101 Inst->setVolatile(IsVolatile);
102 Inst->setWeak(IsWeak);
103 auto *PreviousVal = Builder->CreateExtractValue(Inst, /*Idxs=*/0);
104 auto *SuccessFailureVal = Builder->CreateExtractValue(Inst, /*Idxs=*/1);
105 return std::make_pair(PreviousVal, SuccessFailureVal);
106}
107
108std::pair<LoadInst *, AllocaInst *>
111 Type *SizedIntTy = Type::getIntNTy(Ctx, getAtomicSizeInBits());
112 Type *ResultTy;
114 AttributeList Attr;
115 Module *M = Builder->GetInsertBlock()->getModule();
116 const DataLayout &DL = M->getDataLayout();
117 Args.push_back(
118 ConstantInt::get(DL.getIntPtrType(Ctx), this->getAtomicSizeInBits() / 8));
119
120 Value *PtrVal = getAtomicPointer();
121 PtrVal = Builder->CreateAddrSpaceCast(PtrVal, PointerType::getUnqual(Ctx));
122 Args.push_back(PtrVal);
123
124 auto CurrentIP = Builder->saveIP();
125 Builder->restoreIP(AllocaIP);
126 AllocaInst *AllocaResult =
127 CreateAlloca(Ty, getAtomicPointer()->getName() + "atomic.temp.load");
128 Builder->restoreIP(CurrentIP);
129 const Align AllocaAlignment = DL.getPrefTypeAlign(SizedIntTy);
130 AllocaResult->setAlignment(AllocaAlignment);
131 Args.push_back(AllocaResult);
132 Constant *OrderingVal =
133 ConstantInt::get(Type::getInt32Ty(Ctx), (int)toCABI(AO));
134 Args.push_back(OrderingVal);
135
136 ResultTy = Type::getVoidTy(Ctx);
138 for (Value *Arg : Args)
139 ArgTys.push_back(Arg->getType());
140 FunctionType *FnType = FunctionType::get(ResultTy, ArgTys, false);
141 FunctionCallee LibcallFn =
142 M->getOrInsertFunction("__atomic_load", FnType, Attr);
143 CallInst *Call = Builder->CreateCall(LibcallFn, Args);
144 Call->setAttributes(Attr);
145 return std::make_pair(
146 Builder->CreateAlignedLoad(Ty, AllocaResult, AllocaAlignment),
147 AllocaResult);
148}
149
153 AttributeList Attr;
154 Module *M = Builder->GetInsertBlock()->getModule();
155 const DataLayout &DL = M->getDataLayout();
156 Args.push_back(
157 ConstantInt::get(DL.getIntPtrType(Ctx), this->getAtomicSizeInBits() / 8));
158
159 Value *PtrVal = getAtomicPointer();
160 PtrVal = Builder->CreateAddrSpaceCast(PtrVal, PointerType::getUnqual(Ctx));
161 Args.push_back(PtrVal);
162
163 auto CurrentIP = Builder->saveIP();
164 Builder->restoreIP(AllocaIP);
165 Value *SourceAlloca = Builder->CreateAlloca(Source->getType());
166 Builder->restoreIP(CurrentIP);
167 Builder->CreateStore(Source, SourceAlloca);
168 SourceAlloca = Builder->CreatePointerBitCastOrAddrSpaceCast(
169 SourceAlloca, Builder->getPtrTy());
170 Args.push_back(SourceAlloca);
171
172 Constant *OrderingVal =
173 ConstantInt::get(Type::getInt32Ty(Ctx), (int)toCABI(AO));
174 Args.push_back(OrderingVal);
175
177 for (Value *Arg : Args)
178 ArgTys.push_back(Arg->getType());
179 FunctionType *FnType = FunctionType::get(Type::getVoidTy(Ctx), ArgTys, false);
180 FunctionCallee LibcallFn =
181 M->getOrInsertFunction("__atomic_store", FnType, Attr);
182 CallInst *Call = Builder->CreateCall(LibcallFn, Args);
183 Call->setAttributes(Attr);
184}
185
186std::pair<Value *, Value *> AtomicInfo::EmitAtomicCompareExchange(
187 Value *ExpectedVal, Value *DesiredVal, AtomicOrdering Success,
188 AtomicOrdering Failure, bool IsVolatile, bool IsWeak) {
189 if (shouldUseLibcall())
190 return EmitAtomicCompareExchangeLibcall(ExpectedVal, DesiredVal, Success,
191 Failure);
192
193 auto Res = EmitAtomicCompareExchangeOp(ExpectedVal, DesiredVal, Success,
194 Failure, IsVolatile, IsWeak);
195 return Res;
196}
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static StringRef getName(Value *V)
Class for arbitrary precision integers.
Definition APInt.h:78
an instruction to allocate memory on the stack
void setAlignment(Align Align)
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
Align AtomicAlign
Definition Atomic.h:23
IRBuilderBase * Builder
Definition Atomic.h:19
LLVM_ABI std::pair< Value *, Value * > EmitAtomicCompareExchange(Value *ExpectedVal, Value *DesiredVal, AtomicOrdering Success, AtomicOrdering Failure, bool IsVolatile, bool IsWeak)
Definition Atomic.cpp:186
virtual AllocaInst * CreateAlloca(Type *Ty, const Twine &Name) const =0
LLVM_ABI std::pair< LoadInst *, AllocaInst * > EmitAtomicLoadLibcall(AtomicOrdering AO)
Definition Atomic.cpp:109
LLVM_ABI std::pair< Value *, Value * > EmitAtomicCompareExchangeOp(Value *ExpectedVal, Value *DesiredVal, AtomicOrdering Success, AtomicOrdering Failure, bool IsVolatile=false, bool IsWeak=false)
Definition Atomic.cpp:91
uint64_t getAtomicSizeInBits() const
Definition Atomic.h:39
LLVM_ABI Value * EmitAtomicLoadOp(AtomicOrdering AO, bool IsVolatile, bool CmpXchg=false)
Definition Atomic.cpp:22
virtual Value * getAtomicPointer() const =0
LLVM_ABI std::pair< Value *, Value * > EmitAtomicCompareExchangeLibcall(Value *ExpectedVal, Value *DesiredVal, AtomicOrdering Success, AtomicOrdering Failure)
Definition Atomic.cpp:57
LLVM_ABI bool shouldCastToInt(Type *ValTy, bool CmpXchg)
Definition Atomic.cpp:16
uint64_t AtomicSizeInBits
Definition Atomic.h:21
LLVM_ABI void EmitAtomicStoreLibcall(AtomicOrdering AO, Value *Source)
Definition Atomic.cpp:150
IRBuilderBase::InsertPoint AllocaIP
Definition Atomic.h:26
LLVMContext & getLLVMContext() const
Definition Atomic.h:57
Value * getAtomicAddressAsAtomicIntPointer() const
Definition Atomic.h:86
virtual void decorateWithTBAA(Instruction *I)=0
LLVM_ABI CallInst * EmitAtomicLibcall(StringRef fnName, Type *ResultType, ArrayRef< Value * > Args)
Definition Atomic.cpp:37
Value * getAtomicSizeValue() const
Definition Atomic.h:67
bool shouldUseLibcall() const
Definition Atomic.h:41
Align getAtomicAlignment() const
Definition Atomic.h:38
This class represents a function call, abstracting a target machine's calling convention.
This is an important base class in LLVM.
Definition Constant.h:43
static LLVM_ABI Constant * getIntegerValue(Type *Ty, const APInt &V)
Return the value for an integer or pointer constant, or a vector thereof, with the given scalar value...
A parsed version of the target data layout string in and methods for querying it.
Definition DataLayout.h:64
A handy container for a FunctionType+Callee-pointer pair, which can be passed around as a single enti...
Class to represent function types.
static LLVM_ABI FunctionType * get(Type *Result, ArrayRef< Type * > Params, bool isVarArg)
This static method is the primary way of constructing a FunctionType.
static LLVM_ABI IntegerType * get(LLVMContext &C, unsigned NumBits)
This static method is the primary way of constructing an IntegerType.
Definition Type.cpp:354
This is an important class for using LLVM in a threaded context.
Definition LLVMContext.h:68
An instruction for reading from memory.
A Module instance is used to store all the information related to an LLVM module.
Definition Module.h:67
static PointerType * getUnqual(Type *ElementType)
This constructs a pointer to an object of the specified type in the default address space (address sp...
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
StringRef - Represent a constant reference to a string, i.e.
Definition StringRef.h:55
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:46
bool isX86_FP80Ty() const
Return true if this is x86 long double.
Definition Type.h:161
static LLVM_ABI IntegerType * getInt32Ty(LLVMContext &C)
Definition Type.cpp:313
bool isPointerTy() const
True if this is an instance of PointerType.
Definition Type.h:284
static LLVM_ABI Type * getVoidTy(LLVMContext &C)
Definition Type.cpp:286
static LLVM_ABI IntegerType * getInt1Ty(LLVMContext &C)
Definition Type.cpp:310
bool isFloatingPointTy() const
Return true if this is one of the floating-point types.
Definition Type.h:186
bool isIntegerTy() const
True if this is an instance of IntegerType.
Definition Type.h:257
static LLVM_ABI IntegerType * getIntNTy(LLVMContext &C, unsigned N)
Definition Type.cpp:317
LLVM Value Representation.
Definition Value.h:75
CallInst * Call
@ System
Synchronized with respect to all concurrently executing threads.
Definition LLVMContext.h:58
This is an optimization pass for GlobalISel generic memory operations.
AtomicOrderingCABI toCABI(AtomicOrdering AO)
@ Success
The lock was released successfully.
AtomicOrdering
Atomic ordering for LLVM's memory model.
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition Alignment.h:39