1fc207f2dSJohn McCall //===--- CGAtomic.cpp - Emit LLVM IR for atomic operations ----------------===//
2fc207f2dSJohn McCall //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6fc207f2dSJohn McCall //
7fc207f2dSJohn McCall //===----------------------------------------------------------------------===//
8fc207f2dSJohn McCall //
9fc207f2dSJohn McCall // This file contains the code for emitting atomic operations.
10fc207f2dSJohn McCall //
11fc207f2dSJohn McCall //===----------------------------------------------------------------------===//
12fc207f2dSJohn McCall
13fc207f2dSJohn McCall #include "CGCall.h"
14b57056f4SAlexey Bataev #include "CGRecordLayout.h"
159670f847SMehdi Amini #include "CodeGenFunction.h"
16fc207f2dSJohn McCall #include "CodeGenModule.h"
1739195062SYaxun Liu #include "TargetInfo.h"
18fc207f2dSJohn McCall #include "clang/AST/ASTContext.h"
19a8e7df36SMark Lacey #include "clang/CodeGen/CGFunctionInfo.h"
205337c748SRichard Trieu #include "clang/Frontend/FrontendDiagnostic.h"
2130d652a4SYaxun Liu #include "llvm/ADT/DenseMap.h"
22fc207f2dSJohn McCall #include "llvm/IR/DataLayout.h"
23fc207f2dSJohn McCall #include "llvm/IR/Intrinsics.h"
24a8ec7eb9SJohn McCall #include "llvm/IR/Operator.h"
25fc207f2dSJohn McCall
26fc207f2dSJohn McCall using namespace clang;
27fc207f2dSJohn McCall using namespace CodeGen;
28fc207f2dSJohn McCall
29a8ec7eb9SJohn McCall namespace {
30a8ec7eb9SJohn McCall class AtomicInfo {
31a8ec7eb9SJohn McCall CodeGenFunction &CGF;
32a8ec7eb9SJohn McCall QualType AtomicTy;
33a8ec7eb9SJohn McCall QualType ValueTy;
34a8ec7eb9SJohn McCall uint64_t AtomicSizeInBits;
35a8ec7eb9SJohn McCall uint64_t ValueSizeInBits;
36a8ec7eb9SJohn McCall CharUnits AtomicAlign;
37a8ec7eb9SJohn McCall CharUnits ValueAlign;
38a8ec7eb9SJohn McCall TypeEvaluationKind EvaluationKind;
39a8ec7eb9SJohn McCall bool UseLibcall;
40b57056f4SAlexey Bataev LValue LVal;
41b57056f4SAlexey Bataev CGBitFieldInfo BFI;
42a8ec7eb9SJohn McCall public:
AtomicInfo(CodeGenFunction & CGF,LValue & lvalue)43b57056f4SAlexey Bataev AtomicInfo(CodeGenFunction &CGF, LValue &lvalue)
44b57056f4SAlexey Bataev : CGF(CGF), AtomicSizeInBits(0), ValueSizeInBits(0),
45b57056f4SAlexey Bataev EvaluationKind(TEK_Scalar), UseLibcall(true) {
46b57056f4SAlexey Bataev assert(!lvalue.isGlobalReg());
4702e1ec69SAlexey Bataev ASTContext &C = CGF.getContext();
48b57056f4SAlexey Bataev if (lvalue.isSimple()) {
49b57056f4SAlexey Bataev AtomicTy = lvalue.getType();
50b57056f4SAlexey Bataev if (auto *ATy = AtomicTy->getAs<AtomicType>())
51b57056f4SAlexey Bataev ValueTy = ATy->getValueType();
52b57056f4SAlexey Bataev else
53b57056f4SAlexey Bataev ValueTy = AtomicTy;
54b57056f4SAlexey Bataev EvaluationKind = CGF.getEvaluationKind(ValueTy);
5502e1ec69SAlexey Bataev
5634b57499SDavid Majnemer uint64_t ValueAlignInBits;
5734b57499SDavid Majnemer uint64_t AtomicAlignInBits;
5834b57499SDavid Majnemer TypeInfo ValueTI = C.getTypeInfo(ValueTy);
5934b57499SDavid Majnemer ValueSizeInBits = ValueTI.Width;
6034b57499SDavid Majnemer ValueAlignInBits = ValueTI.Align;
61a8ec7eb9SJohn McCall
6234b57499SDavid Majnemer TypeInfo AtomicTI = C.getTypeInfo(AtomicTy);
6334b57499SDavid Majnemer AtomicSizeInBits = AtomicTI.Width;
6434b57499SDavid Majnemer AtomicAlignInBits = AtomicTI.Align;
65a8ec7eb9SJohn McCall
66a8ec7eb9SJohn McCall assert(ValueSizeInBits <= AtomicSizeInBits);
6734b57499SDavid Majnemer assert(ValueAlignInBits <= AtomicAlignInBits);
68a8ec7eb9SJohn McCall
6934b57499SDavid Majnemer AtomicAlign = C.toCharUnitsFromBits(AtomicAlignInBits);
7034b57499SDavid Majnemer ValueAlign = C.toCharUnitsFromBits(ValueAlignInBits);
71a8ec7eb9SJohn McCall if (lvalue.getAlignment().isZero())
72a8ec7eb9SJohn McCall lvalue.setAlignment(AtomicAlign);
73a8ec7eb9SJohn McCall
74b57056f4SAlexey Bataev LVal = lvalue;
75b57056f4SAlexey Bataev } else if (lvalue.isBitField()) {
76b8329261SAlexey Bataev ValueTy = lvalue.getType();
77b8329261SAlexey Bataev ValueSizeInBits = C.getTypeSize(ValueTy);
78b57056f4SAlexey Bataev auto &OrigBFI = lvalue.getBitFieldInfo();
79b57056f4SAlexey Bataev auto Offset = OrigBFI.Offset % C.toBits(lvalue.getAlignment());
80b57056f4SAlexey Bataev AtomicSizeInBits = C.toBits(
81b57056f4SAlexey Bataev C.toCharUnitsFromBits(Offset + OrigBFI.Size + C.getCharWidth() - 1)
8283aa9794SRui Ueyama .alignTo(lvalue.getAlignment()));
837f416cc4SJohn McCall auto VoidPtrAddr = CGF.EmitCastToVoidPtr(lvalue.getBitFieldPointer());
84b57056f4SAlexey Bataev auto OffsetInChars =
85b57056f4SAlexey Bataev (C.toCharUnitsFromBits(OrigBFI.Offset) / lvalue.getAlignment()) *
86b57056f4SAlexey Bataev lvalue.getAlignment();
87b57056f4SAlexey Bataev VoidPtrAddr = CGF.Builder.CreateConstGEP1_64(
88357756ecSNikita Popov CGF.Int8Ty, VoidPtrAddr, OffsetInChars.getQuantity());
8950650766SNikita Popov llvm::Type *IntTy = CGF.Builder.getIntNTy(AtomicSizeInBits);
90b57056f4SAlexey Bataev auto Addr = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
9150650766SNikita Popov VoidPtrAddr, IntTy->getPointerTo(), "atomic_bitfield_base");
92b57056f4SAlexey Bataev BFI = OrigBFI;
93b57056f4SAlexey Bataev BFI.Offset = Offset;
94b57056f4SAlexey Bataev BFI.StorageSize = AtomicSizeInBits;
9503ce2a16SUlrich Weigand BFI.StorageOffset += OffsetInChars;
9650650766SNikita Popov LVal = LValue::MakeBitfield(Address(Addr, IntTy, lvalue.getAlignment()),
97d17f12a3SIvan A. Kosarev BFI, lvalue.getType(), lvalue.getBaseInfo(),
98d17f12a3SIvan A. Kosarev lvalue.getTBAAInfo());
99b8329261SAlexey Bataev AtomicTy = C.getIntTypeForBitwidth(AtomicSizeInBits, OrigBFI.IsSigned);
100b8329261SAlexey Bataev if (AtomicTy.isNull()) {
101b8329261SAlexey Bataev llvm::APInt Size(
102b8329261SAlexey Bataev /*numBits=*/32,
103b8329261SAlexey Bataev C.toCharUnitsFromBits(AtomicSizeInBits).getQuantity());
104772e266fSRichard Smith AtomicTy =
105772e266fSRichard Smith C.getConstantArrayType(C.CharTy, Size, nullptr, ArrayType::Normal,
106b8329261SAlexey Bataev /*IndexTypeQuals=*/0);
107b8329261SAlexey Bataev }
108b8329261SAlexey Bataev AtomicAlign = ValueAlign = lvalue.getAlignment();
109b57056f4SAlexey Bataev } else if (lvalue.isVectorElt()) {
110e0712019SSimon Pilgrim ValueTy = lvalue.getType()->castAs<VectorType>()->getElementType();
111b8329261SAlexey Bataev ValueSizeInBits = C.getTypeSize(ValueTy);
112b8329261SAlexey Bataev AtomicTy = lvalue.getType();
113b8329261SAlexey Bataev AtomicSizeInBits = C.getTypeSize(AtomicTy);
114b8329261SAlexey Bataev AtomicAlign = ValueAlign = lvalue.getAlignment();
115b57056f4SAlexey Bataev LVal = lvalue;
116b57056f4SAlexey Bataev } else {
117b57056f4SAlexey Bataev assert(lvalue.isExtVectorElt());
118b8329261SAlexey Bataev ValueTy = lvalue.getType();
119b8329261SAlexey Bataev ValueSizeInBits = C.getTypeSize(ValueTy);
120b8329261SAlexey Bataev AtomicTy = ValueTy = CGF.getContext().getExtVectorType(
12119e883fcSChristopher Tetreault lvalue.getType(), cast<llvm::FixedVectorType>(
122f22fbe3aSChristopher Tetreault lvalue.getExtVectorAddress().getElementType())
123f22fbe3aSChristopher Tetreault ->getNumElements());
124b8329261SAlexey Bataev AtomicSizeInBits = C.getTypeSize(AtomicTy);
125b8329261SAlexey Bataev AtomicAlign = ValueAlign = lvalue.getAlignment();
126b57056f4SAlexey Bataev LVal = lvalue;
127b57056f4SAlexey Bataev }
128452d8e11SAlexey Bataev UseLibcall = !C.getTargetInfo().hasBuiltinAtomic(
129452d8e11SAlexey Bataev AtomicSizeInBits, C.toBits(lvalue.getAlignment()));
130a8ec7eb9SJohn McCall }
131a8ec7eb9SJohn McCall
getAtomicType() const132a8ec7eb9SJohn McCall QualType getAtomicType() const { return AtomicTy; }
getValueType() const133a8ec7eb9SJohn McCall QualType getValueType() const { return ValueTy; }
getAtomicAlignment() const134a8ec7eb9SJohn McCall CharUnits getAtomicAlignment() const { return AtomicAlign; }
getAtomicSizeInBits() const135a8ec7eb9SJohn McCall uint64_t getAtomicSizeInBits() const { return AtomicSizeInBits; }
getValueSizeInBits() const136452d8e11SAlexey Bataev uint64_t getValueSizeInBits() const { return ValueSizeInBits; }
getEvaluationKind() const137a8ec7eb9SJohn McCall TypeEvaluationKind getEvaluationKind() const { return EvaluationKind; }
shouldUseLibcall() const138a8ec7eb9SJohn McCall bool shouldUseLibcall() const { return UseLibcall; }
getAtomicLValue() const139b57056f4SAlexey Bataev const LValue &getAtomicLValue() const { return LVal; }
getAtomicPointer() const1407f416cc4SJohn McCall llvm::Value *getAtomicPointer() const {
141b8329261SAlexey Bataev if (LVal.isSimple())
142f139ae3dSAkira Hatanaka return LVal.getPointer(CGF);
143b8329261SAlexey Bataev else if (LVal.isBitField())
1447f416cc4SJohn McCall return LVal.getBitFieldPointer();
145b8329261SAlexey Bataev else if (LVal.isVectorElt())
1467f416cc4SJohn McCall return LVal.getVectorPointer();
147b8329261SAlexey Bataev assert(LVal.isExtVectorElt());
1487f416cc4SJohn McCall return LVal.getExtVectorPointer();
1497f416cc4SJohn McCall }
getAtomicAddress() const1507f416cc4SJohn McCall Address getAtomicAddress() const {
151e487ddc5SArthur Eubanks llvm::Type *ElTy;
152e487ddc5SArthur Eubanks if (LVal.isSimple())
153e487ddc5SArthur Eubanks ElTy = LVal.getAddress(CGF).getElementType();
154e487ddc5SArthur Eubanks else if (LVal.isBitField())
155e487ddc5SArthur Eubanks ElTy = LVal.getBitFieldAddress().getElementType();
156e487ddc5SArthur Eubanks else if (LVal.isVectorElt())
157e487ddc5SArthur Eubanks ElTy = LVal.getVectorAddress().getElementType();
158e487ddc5SArthur Eubanks else
159e487ddc5SArthur Eubanks ElTy = LVal.getExtVectorAddress().getElementType();
160e487ddc5SArthur Eubanks return Address(getAtomicPointer(), ElTy, getAtomicAlignment());
1617f416cc4SJohn McCall }
1627f416cc4SJohn McCall
getAtomicAddressAsAtomicIntPointer() const1637f416cc4SJohn McCall Address getAtomicAddressAsAtomicIntPointer() const {
1647f416cc4SJohn McCall return emitCastToAtomicIntPointer(getAtomicAddress());
165b8329261SAlexey Bataev }
166a8ec7eb9SJohn McCall
167a8ec7eb9SJohn McCall /// Is the atomic size larger than the underlying value type?
168a8ec7eb9SJohn McCall ///
169a8ec7eb9SJohn McCall /// Note that the absence of padding does not mean that atomic
170a8ec7eb9SJohn McCall /// objects are completely interchangeable with non-atomic
171a8ec7eb9SJohn McCall /// objects: we might have promoted the alignment of a type
172a8ec7eb9SJohn McCall /// without making it bigger.
hasPadding() const173a8ec7eb9SJohn McCall bool hasPadding() const {
174a8ec7eb9SJohn McCall return (ValueSizeInBits != AtomicSizeInBits);
175a8ec7eb9SJohn McCall }
176a8ec7eb9SJohn McCall
177b57056f4SAlexey Bataev bool emitMemSetZeroIfNecessary() const;
178a8ec7eb9SJohn McCall
getAtomicSizeValue() const179a8ec7eb9SJohn McCall llvm::Value *getAtomicSizeValue() const {
180a8ec7eb9SJohn McCall CharUnits size = CGF.getContext().toCharUnitsFromBits(AtomicSizeInBits);
181a8ec7eb9SJohn McCall return CGF.CGM.getSize(size);
182a8ec7eb9SJohn McCall }
183a8ec7eb9SJohn McCall
184cc2a6e06STim Northover /// Cast the given pointer to an integer pointer suitable for atomic
185cc2a6e06STim Northover /// operations if the source.
186cc2a6e06STim Northover Address emitCastToAtomicIntPointer(Address Addr) const;
187cc2a6e06STim Northover
188cc2a6e06STim Northover /// If Addr is compatible with the iN that will be used for an atomic
189cc2a6e06STim Northover /// operation, bitcast it. Otherwise, create a temporary that is suitable
190cc2a6e06STim Northover /// and copy the value across.
191cc2a6e06STim Northover Address convertToAtomicIntPointer(Address Addr) const;
192a8ec7eb9SJohn McCall
193a8ec7eb9SJohn McCall /// Turn an atomic-layout object into an r-value.
1947f416cc4SJohn McCall RValue convertAtomicTempToRValue(Address addr, AggValueSlot resultSlot,
195b8329261SAlexey Bataev SourceLocation loc, bool AsValue) const;
196a8ec7eb9SJohn McCall
1979fc8faf9SAdrian Prantl /// Converts a rvalue to integer value.
198452d8e11SAlexey Bataev llvm::Value *convertRValueToInt(RValue RVal) const;
199452d8e11SAlexey Bataev
200b8329261SAlexey Bataev RValue ConvertIntToValueOrAtomic(llvm::Value *IntVal,
201b8329261SAlexey Bataev AggValueSlot ResultSlot,
202b8329261SAlexey Bataev SourceLocation Loc, bool AsValue) const;
203452d8e11SAlexey Bataev
204a8ec7eb9SJohn McCall /// Copy an atomic r-value into atomic-layout memory.
205b57056f4SAlexey Bataev void emitCopyIntoMemory(RValue rvalue) const;
206a8ec7eb9SJohn McCall
207a8ec7eb9SJohn McCall /// Project an l-value down to the value field.
projectValue() const208b57056f4SAlexey Bataev LValue projectValue() const {
209b57056f4SAlexey Bataev assert(LVal.isSimple());
2107f416cc4SJohn McCall Address addr = getAtomicAddress();
211a8ec7eb9SJohn McCall if (hasPadding())
212751fe286SJames Y Knight addr = CGF.Builder.CreateStructGEP(addr, 0);
213a8ec7eb9SJohn McCall
2147f416cc4SJohn McCall return LValue::MakeAddr(addr, getValueType(), CGF.getContext(),
215383890baSIvan A. Kosarev LVal.getBaseInfo(), LVal.getTBAAInfo());
216a8ec7eb9SJohn McCall }
217a8ec7eb9SJohn McCall
2189fc8faf9SAdrian Prantl /// Emits atomic load.
219b8329261SAlexey Bataev /// \returns Loaded value.
220b8329261SAlexey Bataev RValue EmitAtomicLoad(AggValueSlot ResultSlot, SourceLocation Loc,
221b8329261SAlexey Bataev bool AsValue, llvm::AtomicOrdering AO,
222b8329261SAlexey Bataev bool IsVolatile);
223b8329261SAlexey Bataev
2249fc8faf9SAdrian Prantl /// Emits atomic compare-and-exchange sequence.
225b8329261SAlexey Bataev /// \param Expected Expected value.
226b8329261SAlexey Bataev /// \param Desired Desired value.
227b8329261SAlexey Bataev /// \param Success Atomic ordering for success operation.
228b8329261SAlexey Bataev /// \param Failure Atomic ordering for failed operation.
229b8329261SAlexey Bataev /// \param IsWeak true if atomic operation is weak, false otherwise.
230b8329261SAlexey Bataev /// \returns Pair of values: previous value from storage (value type) and
231b8329261SAlexey Bataev /// boolean flag (i1 type) with true if success and false otherwise.
23292f4ef10SJF Bastien std::pair<RValue, llvm::Value *>
23392f4ef10SJF Bastien EmitAtomicCompareExchange(RValue Expected, RValue Desired,
23492f4ef10SJF Bastien llvm::AtomicOrdering Success =
23592f4ef10SJF Bastien llvm::AtomicOrdering::SequentiallyConsistent,
23692f4ef10SJF Bastien llvm::AtomicOrdering Failure =
23792f4ef10SJF Bastien llvm::AtomicOrdering::SequentiallyConsistent,
238b8329261SAlexey Bataev bool IsWeak = false);
239b8329261SAlexey Bataev
2409fc8faf9SAdrian Prantl /// Emits atomic update.
241d16af5dfSNAKAMURA Takumi /// \param AO Atomic ordering.
242d16af5dfSNAKAMURA Takumi /// \param UpdateOp Update operation for the current lvalue.
243f0ab553fSAlexey Bataev void EmitAtomicUpdate(llvm::AtomicOrdering AO,
244f0ab553fSAlexey Bataev const llvm::function_ref<RValue(RValue)> &UpdateOp,
245f0ab553fSAlexey Bataev bool IsVolatile);
2469fc8faf9SAdrian Prantl /// Emits atomic update.
247d16af5dfSNAKAMURA Takumi /// \param AO Atomic ordering.
248f0ab553fSAlexey Bataev void EmitAtomicUpdate(llvm::AtomicOrdering AO, RValue UpdateRVal,
249f0ab553fSAlexey Bataev bool IsVolatile);
250f0ab553fSAlexey Bataev
251a8ec7eb9SJohn McCall /// Materialize an atomic r-value in atomic-layout memory.
2527f416cc4SJohn McCall Address materializeRValue(RValue rvalue) const;
253a8ec7eb9SJohn McCall
2549fc8faf9SAdrian Prantl /// Creates temp alloca for intermediate operations on atomic value.
255cc2a6e06STim Northover Address CreateTempAlloca() const;
256a8ec7eb9SJohn McCall private:
257a8ec7eb9SJohn McCall bool requiresMemSetZero(llvm::Type *type) const;
258b8329261SAlexey Bataev
259b8329261SAlexey Bataev
2609fc8faf9SAdrian Prantl /// Emits atomic load as a libcall.
261b8329261SAlexey Bataev void EmitAtomicLoadLibcall(llvm::Value *AddForLoaded,
262b8329261SAlexey Bataev llvm::AtomicOrdering AO, bool IsVolatile);
2639fc8faf9SAdrian Prantl /// Emits atomic load as LLVM instruction.
264b8329261SAlexey Bataev llvm::Value *EmitAtomicLoadOp(llvm::AtomicOrdering AO, bool IsVolatile);
2659fc8faf9SAdrian Prantl /// Emits atomic compare-and-exchange op as a libcall.
266f0ab553fSAlexey Bataev llvm::Value *EmitAtomicCompareExchangeLibcall(
267f0ab553fSAlexey Bataev llvm::Value *ExpectedAddr, llvm::Value *DesiredAddr,
26892f4ef10SJF Bastien llvm::AtomicOrdering Success =
26992f4ef10SJF Bastien llvm::AtomicOrdering::SequentiallyConsistent,
27092f4ef10SJF Bastien llvm::AtomicOrdering Failure =
27192f4ef10SJF Bastien llvm::AtomicOrdering::SequentiallyConsistent);
2729fc8faf9SAdrian Prantl /// Emits atomic compare-and-exchange op as LLVM instruction.
273f0ab553fSAlexey Bataev std::pair<llvm::Value *, llvm::Value *> EmitAtomicCompareExchangeOp(
274f0ab553fSAlexey Bataev llvm::Value *ExpectedVal, llvm::Value *DesiredVal,
27592f4ef10SJF Bastien llvm::AtomicOrdering Success =
27692f4ef10SJF Bastien llvm::AtomicOrdering::SequentiallyConsistent,
27792f4ef10SJF Bastien llvm::AtomicOrdering Failure =
27892f4ef10SJF Bastien llvm::AtomicOrdering::SequentiallyConsistent,
279b8329261SAlexey Bataev bool IsWeak = false);
2809fc8faf9SAdrian Prantl /// Emit atomic update as libcalls.
281f0ab553fSAlexey Bataev void
282f0ab553fSAlexey Bataev EmitAtomicUpdateLibcall(llvm::AtomicOrdering AO,
283f0ab553fSAlexey Bataev const llvm::function_ref<RValue(RValue)> &UpdateOp,
284f0ab553fSAlexey Bataev bool IsVolatile);
2859fc8faf9SAdrian Prantl /// Emit atomic update as LLVM instructions.
286f0ab553fSAlexey Bataev void EmitAtomicUpdateOp(llvm::AtomicOrdering AO,
287f0ab553fSAlexey Bataev const llvm::function_ref<RValue(RValue)> &UpdateOp,
288f0ab553fSAlexey Bataev bool IsVolatile);
2899fc8faf9SAdrian Prantl /// Emit atomic update as libcalls.
290f0ab553fSAlexey Bataev void EmitAtomicUpdateLibcall(llvm::AtomicOrdering AO, RValue UpdateRVal,
291f0ab553fSAlexey Bataev bool IsVolatile);
2929fc8faf9SAdrian Prantl /// Emit atomic update as LLVM instructions.
293f0ab553fSAlexey Bataev void EmitAtomicUpdateOp(llvm::AtomicOrdering AO, RValue UpdateRal,
294f0ab553fSAlexey Bataev bool IsVolatile);
295a8ec7eb9SJohn McCall };
296ab9db510SAlexander Kornienko }
297a8ec7eb9SJohn McCall
CreateTempAlloca() const2987f416cc4SJohn McCall Address AtomicInfo::CreateTempAlloca() const {
2997f416cc4SJohn McCall Address TempAlloca = CGF.CreateMemTemp(
300b8329261SAlexey Bataev (LVal.isBitField() && ValueSizeInBits > AtomicSizeInBits) ? ValueTy
301b8329261SAlexey Bataev : AtomicTy,
3027f416cc4SJohn McCall getAtomicAlignment(),
303b8329261SAlexey Bataev "atomic-temp");
304b8329261SAlexey Bataev // Cast to pointer to value type for bitfields.
305b8329261SAlexey Bataev if (LVal.isBitField())
306b8329261SAlexey Bataev return CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
307*d112cc27SAkira Hatanaka TempAlloca, getAtomicAddress().getType(),
308*d112cc27SAkira Hatanaka getAtomicAddress().getElementType());
309b8329261SAlexey Bataev return TempAlloca;
310b8329261SAlexey Bataev }
311b8329261SAlexey Bataev
emitAtomicLibcall(CodeGenFunction & CGF,StringRef fnName,QualType resultType,CallArgList & args)312a8ec7eb9SJohn McCall static RValue emitAtomicLibcall(CodeGenFunction &CGF,
313a8ec7eb9SJohn McCall StringRef fnName,
314a8ec7eb9SJohn McCall QualType resultType,
315a8ec7eb9SJohn McCall CallArgList &args) {
316a8ec7eb9SJohn McCall const CGFunctionInfo &fnInfo =
317c56a8b32SJohn McCall CGF.CGM.getTypes().arrangeBuiltinFunctionCall(resultType, args);
318a8ec7eb9SJohn McCall llvm::FunctionType *fnTy = CGF.CGM.getTypes().GetFunctionType(fnInfo);
319d2cc6c2dSSerge Guelton llvm::AttrBuilder fnAttrB(CGF.getLLVMContext());
320909a851dSGui Andrade fnAttrB.addAttribute(llvm::Attribute::NoUnwind);
321909a851dSGui Andrade fnAttrB.addAttribute(llvm::Attribute::WillReturn);
322909a851dSGui Andrade llvm::AttributeList fnAttrs = llvm::AttributeList::get(
323909a851dSGui Andrade CGF.getLLVMContext(), llvm::AttributeList::FunctionIndex, fnAttrB);
324909a851dSGui Andrade
325909a851dSGui Andrade llvm::FunctionCallee fn =
326909a851dSGui Andrade CGF.CGM.CreateRuntimeFunction(fnTy, fnName, fnAttrs);
327b92ab1afSJohn McCall auto callee = CGCallee::forDirect(fn);
328b92ab1afSJohn McCall return CGF.EmitCall(fnInfo, callee, ReturnValueSlot(), args);
329a8ec7eb9SJohn McCall }
330a8ec7eb9SJohn McCall
331a8ec7eb9SJohn McCall /// Does a store of the given IR type modify the full expected width?
isFullSizeType(CodeGenModule & CGM,llvm::Type * type,uint64_t expectedSize)332a8ec7eb9SJohn McCall static bool isFullSizeType(CodeGenModule &CGM, llvm::Type *type,
333a8ec7eb9SJohn McCall uint64_t expectedSize) {
334a8ec7eb9SJohn McCall return (CGM.getDataLayout().getTypeStoreSize(type) * 8 == expectedSize);
335a8ec7eb9SJohn McCall }
336a8ec7eb9SJohn McCall
337a8ec7eb9SJohn McCall /// Does the atomic type require memsetting to zero before initialization?
338a8ec7eb9SJohn McCall ///
339a8ec7eb9SJohn McCall /// The IR type is provided as a way of making certain queries faster.
requiresMemSetZero(llvm::Type * type) const340a8ec7eb9SJohn McCall bool AtomicInfo::requiresMemSetZero(llvm::Type *type) const {
341a8ec7eb9SJohn McCall // If the atomic type has size padding, we definitely need a memset.
342a8ec7eb9SJohn McCall if (hasPadding()) return true;
343a8ec7eb9SJohn McCall
344a8ec7eb9SJohn McCall // Otherwise, do some simple heuristics to try to avoid it:
345a8ec7eb9SJohn McCall switch (getEvaluationKind()) {
346a8ec7eb9SJohn McCall // For scalars and complexes, check whether the store size of the
347a8ec7eb9SJohn McCall // type uses the full size.
348a8ec7eb9SJohn McCall case TEK_Scalar:
349a8ec7eb9SJohn McCall return !isFullSizeType(CGF.CGM, type, AtomicSizeInBits);
350a8ec7eb9SJohn McCall case TEK_Complex:
351a8ec7eb9SJohn McCall return !isFullSizeType(CGF.CGM, type->getStructElementType(0),
352a8ec7eb9SJohn McCall AtomicSizeInBits / 2);
353a8ec7eb9SJohn McCall
354be4504dfSEli Friedman // Padding in structs has an undefined bit pattern. User beware.
355a8ec7eb9SJohn McCall case TEK_Aggregate:
356be4504dfSEli Friedman return false;
357a8ec7eb9SJohn McCall }
358a8ec7eb9SJohn McCall llvm_unreachable("bad evaluation kind");
359a8ec7eb9SJohn McCall }
360a8ec7eb9SJohn McCall
emitMemSetZeroIfNecessary() const361b57056f4SAlexey Bataev bool AtomicInfo::emitMemSetZeroIfNecessary() const {
362b57056f4SAlexey Bataev assert(LVal.isSimple());
36399adacbcSNikita Popov Address addr = LVal.getAddress(CGF);
36499adacbcSNikita Popov if (!requiresMemSetZero(addr.getElementType()))
365be4504dfSEli Friedman return false;
366a8ec7eb9SJohn McCall
367b8329261SAlexey Bataev CGF.Builder.CreateMemSet(
36899adacbcSNikita Popov addr.getPointer(), llvm::ConstantInt::get(CGF.Int8Ty, 0),
369b8329261SAlexey Bataev CGF.getContext().toCharUnitsFromBits(AtomicSizeInBits).getQuantity(),
3701b2842bfSGuillaume Chatelet LVal.getAlignment().getAsAlign());
371be4504dfSEli Friedman return true;
372a8ec7eb9SJohn McCall }
373a8ec7eb9SJohn McCall
emitAtomicCmpXchg(CodeGenFunction & CGF,AtomicExpr * E,bool IsWeak,Address Dest,Address Ptr,Address Val1,Address Val2,uint64_t Size,llvm::AtomicOrdering SuccessOrder,llvm::AtomicOrdering FailureOrder,llvm::SyncScope::ID Scope)374cadbbe15STim Northover static void emitAtomicCmpXchg(CodeGenFunction &CGF, AtomicExpr *E, bool IsWeak,
3757f416cc4SJohn McCall Address Dest, Address Ptr,
3767f416cc4SJohn McCall Address Val1, Address Val2,
3777f416cc4SJohn McCall uint64_t Size,
3789c177223STim Northover llvm::AtomicOrdering SuccessOrder,
37939195062SYaxun Liu llvm::AtomicOrdering FailureOrder,
38039195062SYaxun Liu llvm::SyncScope::ID Scope) {
3819c177223STim Northover // Note that cmpxchg doesn't support weak cmpxchg, at least at the moment.
3827f416cc4SJohn McCall llvm::Value *Expected = CGF.Builder.CreateLoad(Val1);
3837f416cc4SJohn McCall llvm::Value *Desired = CGF.Builder.CreateLoad(Val2);
3849c177223STim Northover
385b49b04bbSTim Northover llvm::AtomicCmpXchgInst *Pair = CGF.Builder.CreateAtomicCmpXchg(
38639195062SYaxun Liu Ptr.getPointer(), Expected, Desired, SuccessOrder, FailureOrder,
38739195062SYaxun Liu Scope);
388b49b04bbSTim Northover Pair->setVolatile(E->isVolatile());
389cadbbe15STim Northover Pair->setWeak(IsWeak);
390938bc1eaSDavid Majnemer
391938bc1eaSDavid Majnemer // Cmp holds the result of the compare-exchange operation: true on success,
392938bc1eaSDavid Majnemer // false on failure.
393b49b04bbSTim Northover llvm::Value *Old = CGF.Builder.CreateExtractValue(Pair, 0);
394b49b04bbSTim Northover llvm::Value *Cmp = CGF.Builder.CreateExtractValue(Pair, 1);
395938bc1eaSDavid Majnemer
396938bc1eaSDavid Majnemer // This basic block is used to hold the store instruction if the operation
397938bc1eaSDavid Majnemer // failed.
398938bc1eaSDavid Majnemer llvm::BasicBlock *StoreExpectedBB =
399938bc1eaSDavid Majnemer CGF.createBasicBlock("cmpxchg.store_expected", CGF.CurFn);
400938bc1eaSDavid Majnemer
401938bc1eaSDavid Majnemer // This basic block is the exit point of the operation, we should end up
402938bc1eaSDavid Majnemer // here regardless of whether or not the operation succeeded.
403938bc1eaSDavid Majnemer llvm::BasicBlock *ContinueBB =
404938bc1eaSDavid Majnemer CGF.createBasicBlock("cmpxchg.continue", CGF.CurFn);
405938bc1eaSDavid Majnemer
406938bc1eaSDavid Majnemer // Update Expected if Expected isn't equal to Old, otherwise branch to the
407938bc1eaSDavid Majnemer // exit point.
408938bc1eaSDavid Majnemer CGF.Builder.CreateCondBr(Cmp, ContinueBB, StoreExpectedBB);
409938bc1eaSDavid Majnemer
410938bc1eaSDavid Majnemer CGF.Builder.SetInsertPoint(StoreExpectedBB);
411938bc1eaSDavid Majnemer // Update the memory at Expected with Old's value.
4127f416cc4SJohn McCall CGF.Builder.CreateStore(Old, Val1);
413938bc1eaSDavid Majnemer // Finally, branch to the exit point.
414938bc1eaSDavid Majnemer CGF.Builder.CreateBr(ContinueBB);
415938bc1eaSDavid Majnemer
416938bc1eaSDavid Majnemer CGF.Builder.SetInsertPoint(ContinueBB);
417938bc1eaSDavid Majnemer // Update the memory at Dest with Cmp's value.
418fc207f2dSJohn McCall CGF.EmitStoreOfScalar(Cmp, CGF.MakeAddrLValue(Dest, E->getType()));
419fc207f2dSJohn McCall }
420fc207f2dSJohn McCall
4219c177223STim Northover /// Given an ordering required on success, emit all possible cmpxchg
4229c177223STim Northover /// instructions to cope with the provided (but possibly only dynamically known)
4239c177223STim Northover /// FailureOrder.
emitAtomicCmpXchgFailureSet(CodeGenFunction & CGF,AtomicExpr * E,bool IsWeak,Address Dest,Address Ptr,Address Val1,Address Val2,llvm::Value * FailureOrderVal,uint64_t Size,llvm::AtomicOrdering SuccessOrder,llvm::SyncScope::ID Scope)4249c177223STim Northover static void emitAtomicCmpXchgFailureSet(CodeGenFunction &CGF, AtomicExpr *E,
425dda2cb17SJF Bastien bool IsWeak, Address Dest, Address Ptr,
426dda2cb17SJF Bastien Address Val1, Address Val2,
4279c177223STim Northover llvm::Value *FailureOrderVal,
4287f416cc4SJohn McCall uint64_t Size,
42939195062SYaxun Liu llvm::AtomicOrdering SuccessOrder,
43039195062SYaxun Liu llvm::SyncScope::ID Scope) {
4319c177223STim Northover llvm::AtomicOrdering FailureOrder;
4329c177223STim Northover if (llvm::ConstantInt *FO = dyn_cast<llvm::ConstantInt>(FailureOrderVal)) {
433dda2cb17SJF Bastien auto FOS = FO->getSExtValue();
434dda2cb17SJF Bastien if (!llvm::isValidAtomicOrderingCABI(FOS))
435dda2cb17SJF Bastien FailureOrder = llvm::AtomicOrdering::Monotonic;
436dda2cb17SJF Bastien else
437dda2cb17SJF Bastien switch ((llvm::AtomicOrderingCABI)FOS) {
438dda2cb17SJF Bastien case llvm::AtomicOrderingCABI::relaxed:
439431e3138SBruno Cardoso Lopes // 31.7.2.18: "The failure argument shall not be memory_order_release
440431e3138SBruno Cardoso Lopes // nor memory_order_acq_rel". Fallback to monotonic.
441dda2cb17SJF Bastien case llvm::AtomicOrderingCABI::release:
442dda2cb17SJF Bastien case llvm::AtomicOrderingCABI::acq_rel:
44392f4ef10SJF Bastien FailureOrder = llvm::AtomicOrdering::Monotonic;
4449c177223STim Northover break;
445dda2cb17SJF Bastien case llvm::AtomicOrderingCABI::consume:
446dda2cb17SJF Bastien case llvm::AtomicOrderingCABI::acquire:
44792f4ef10SJF Bastien FailureOrder = llvm::AtomicOrdering::Acquire;
4489c177223STim Northover break;
449dda2cb17SJF Bastien case llvm::AtomicOrderingCABI::seq_cst:
45092f4ef10SJF Bastien FailureOrder = llvm::AtomicOrdering::SequentiallyConsistent;
4519c177223STim Northover break;
4529c177223STim Northover }
453431e3138SBruno Cardoso Lopes // Prior to c++17, "the failure argument shall be no stronger than the
454431e3138SBruno Cardoso Lopes // success argument". This condition has been lifted and the only
455431e3138SBruno Cardoso Lopes // precondition is 31.7.2.18. Effectively treat this as a DR and skip
456431e3138SBruno Cardoso Lopes // language version checks.
457dda2cb17SJF Bastien emitAtomicCmpXchg(CGF, E, IsWeak, Dest, Ptr, Val1, Val2, Size, SuccessOrder,
45839195062SYaxun Liu FailureOrder, Scope);
4599c177223STim Northover return;
4609c177223STim Northover }
4619c177223STim Northover
4629c177223STim Northover // Create all the relevant BB's
463819e0d10SBruno Cardoso Lopes auto *MonotonicBB = CGF.createBasicBlock("monotonic_fail", CGF.CurFn);
464819e0d10SBruno Cardoso Lopes auto *AcquireBB = CGF.createBasicBlock("acquire_fail", CGF.CurFn);
465819e0d10SBruno Cardoso Lopes auto *SeqCstBB = CGF.createBasicBlock("seqcst_fail", CGF.CurFn);
466819e0d10SBruno Cardoso Lopes auto *ContBB = CGF.createBasicBlock("atomic.continue", CGF.CurFn);
4679c177223STim Northover
4689c177223STim Northover // MonotonicBB is arbitrarily chosen as the default case; in practice, this
4699c177223STim Northover // doesn't matter unless someone is crazy enough to use something that
4709c177223STim Northover // doesn't fold to a constant for the ordering.
471819e0d10SBruno Cardoso Lopes llvm::SwitchInst *SI = CGF.Builder.CreateSwitch(FailureOrderVal, MonotonicBB);
472819e0d10SBruno Cardoso Lopes // Implemented as acquire, since it's the closest in LLVM.
473819e0d10SBruno Cardoso Lopes SI->addCase(CGF.Builder.getInt32((int)llvm::AtomicOrderingCABI::consume),
474819e0d10SBruno Cardoso Lopes AcquireBB);
475819e0d10SBruno Cardoso Lopes SI->addCase(CGF.Builder.getInt32((int)llvm::AtomicOrderingCABI::acquire),
476819e0d10SBruno Cardoso Lopes AcquireBB);
477819e0d10SBruno Cardoso Lopes SI->addCase(CGF.Builder.getInt32((int)llvm::AtomicOrderingCABI::seq_cst),
478819e0d10SBruno Cardoso Lopes SeqCstBB);
479819e0d10SBruno Cardoso Lopes
480819e0d10SBruno Cardoso Lopes // Emit all the different atomics
4819c177223STim Northover CGF.Builder.SetInsertPoint(MonotonicBB);
482cadbbe15STim Northover emitAtomicCmpXchg(CGF, E, IsWeak, Dest, Ptr, Val1, Val2,
48339195062SYaxun Liu Size, SuccessOrder, llvm::AtomicOrdering::Monotonic, Scope);
4849c177223STim Northover CGF.Builder.CreateBr(ContBB);
4859c177223STim Northover
4869c177223STim Northover CGF.Builder.SetInsertPoint(AcquireBB);
487819e0d10SBruno Cardoso Lopes emitAtomicCmpXchg(CGF, E, IsWeak, Dest, Ptr, Val1, Val2, Size, SuccessOrder,
488819e0d10SBruno Cardoso Lopes llvm::AtomicOrdering::Acquire, Scope);
4899c177223STim Northover CGF.Builder.CreateBr(ContBB);
490819e0d10SBruno Cardoso Lopes
4919c177223STim Northover CGF.Builder.SetInsertPoint(SeqCstBB);
49292f4ef10SJF Bastien emitAtomicCmpXchg(CGF, E, IsWeak, Dest, Ptr, Val1, Val2, Size, SuccessOrder,
49339195062SYaxun Liu llvm::AtomicOrdering::SequentiallyConsistent, Scope);
4949c177223STim Northover CGF.Builder.CreateBr(ContBB);
4959c177223STim Northover
4969c177223STim Northover CGF.Builder.SetInsertPoint(ContBB);
4979c177223STim Northover }
4989c177223STim Northover
4995cf58768STim Northover /// Duplicate the atomic min/max operation in conventional IR for the builtin
5005cf58768STim Northover /// variants that return the new rather than the original value.
EmitPostAtomicMinMax(CGBuilderTy & Builder,AtomicExpr::AtomicOp Op,bool IsSigned,llvm::Value * OldVal,llvm::Value * RHS)5015cf58768STim Northover static llvm::Value *EmitPostAtomicMinMax(CGBuilderTy &Builder,
5025cf58768STim Northover AtomicExpr::AtomicOp Op,
5035cf58768STim Northover bool IsSigned,
5045cf58768STim Northover llvm::Value *OldVal,
5055cf58768STim Northover llvm::Value *RHS) {
5065cf58768STim Northover llvm::CmpInst::Predicate Pred;
5075cf58768STim Northover switch (Op) {
5085cf58768STim Northover default:
5095cf58768STim Northover llvm_unreachable("Unexpected min/max operation");
5105cf58768STim Northover case AtomicExpr::AO__atomic_max_fetch:
5115cf58768STim Northover Pred = IsSigned ? llvm::CmpInst::ICMP_SGT : llvm::CmpInst::ICMP_UGT;
5125cf58768STim Northover break;
5135cf58768STim Northover case AtomicExpr::AO__atomic_min_fetch:
5145cf58768STim Northover Pred = IsSigned ? llvm::CmpInst::ICMP_SLT : llvm::CmpInst::ICMP_ULT;
5155cf58768STim Northover break;
5165cf58768STim Northover }
5175cf58768STim Northover llvm::Value *Cmp = Builder.CreateICmp(Pred, OldVal, RHS, "tst");
5185cf58768STim Northover return Builder.CreateSelect(Cmp, OldVal, RHS, "newval");
5195cf58768STim Northover }
5205cf58768STim Northover
EmitAtomicOp(CodeGenFunction & CGF,AtomicExpr * E,Address Dest,Address Ptr,Address Val1,Address Val2,llvm::Value * IsWeak,llvm::Value * FailureOrder,uint64_t Size,llvm::AtomicOrdering Order,llvm::SyncScope::ID Scope)5217f416cc4SJohn McCall static void EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *E, Address Dest,
5227f416cc4SJohn McCall Address Ptr, Address Val1, Address Val2,
523cadbbe15STim Northover llvm::Value *IsWeak, llvm::Value *FailureOrder,
52439195062SYaxun Liu uint64_t Size, llvm::AtomicOrdering Order,
52539195062SYaxun Liu llvm::SyncScope::ID Scope) {
5269c177223STim Northover llvm::AtomicRMWInst::BinOp Op = llvm::AtomicRMWInst::Add;
5275cf58768STim Northover bool PostOpMinMax = false;
5285cf58768STim Northover unsigned PostOp = 0;
5299c177223STim Northover
5309c177223STim Northover switch (E->getOp()) {
5319c177223STim Northover case AtomicExpr::AO__c11_atomic_init:
53239195062SYaxun Liu case AtomicExpr::AO__opencl_atomic_init:
5339c177223STim Northover llvm_unreachable("Already handled!");
5349c177223STim Northover
5359c177223STim Northover case AtomicExpr::AO__c11_atomic_compare_exchange_strong:
536e13246a2SYaxun (Sam) Liu case AtomicExpr::AO__hip_atomic_compare_exchange_strong:
53739195062SYaxun Liu case AtomicExpr::AO__opencl_atomic_compare_exchange_strong:
538cadbbe15STim Northover emitAtomicCmpXchgFailureSet(CGF, E, false, Dest, Ptr, Val1, Val2,
53939195062SYaxun Liu FailureOrder, Size, Order, Scope);
5409c177223STim Northover return;
541cadbbe15STim Northover case AtomicExpr::AO__c11_atomic_compare_exchange_weak:
54239195062SYaxun Liu case AtomicExpr::AO__opencl_atomic_compare_exchange_weak:
543df0560caSAnshil Gandhi case AtomicExpr::AO__hip_atomic_compare_exchange_weak:
544cadbbe15STim Northover emitAtomicCmpXchgFailureSet(CGF, E, true, Dest, Ptr, Val1, Val2,
54539195062SYaxun Liu FailureOrder, Size, Order, Scope);
546cadbbe15STim Northover return;
547cadbbe15STim Northover case AtomicExpr::AO__atomic_compare_exchange:
548cadbbe15STim Northover case AtomicExpr::AO__atomic_compare_exchange_n: {
549cadbbe15STim Northover if (llvm::ConstantInt *IsWeakC = dyn_cast<llvm::ConstantInt>(IsWeak)) {
550cadbbe15STim Northover emitAtomicCmpXchgFailureSet(CGF, E, IsWeakC->getZExtValue(), Dest, Ptr,
55139195062SYaxun Liu Val1, Val2, FailureOrder, Size, Order, Scope);
552cadbbe15STim Northover } else {
553cadbbe15STim Northover // Create all the relevant BB's
554cadbbe15STim Northover llvm::BasicBlock *StrongBB =
555cadbbe15STim Northover CGF.createBasicBlock("cmpxchg.strong", CGF.CurFn);
556cadbbe15STim Northover llvm::BasicBlock *WeakBB = CGF.createBasicBlock("cmxchg.weak", CGF.CurFn);
557cadbbe15STim Northover llvm::BasicBlock *ContBB =
558cadbbe15STim Northover CGF.createBasicBlock("cmpxchg.continue", CGF.CurFn);
559cadbbe15STim Northover
560cadbbe15STim Northover llvm::SwitchInst *SI = CGF.Builder.CreateSwitch(IsWeak, WeakBB);
561cadbbe15STim Northover SI->addCase(CGF.Builder.getInt1(false), StrongBB);
562cadbbe15STim Northover
563cadbbe15STim Northover CGF.Builder.SetInsertPoint(StrongBB);
564cadbbe15STim Northover emitAtomicCmpXchgFailureSet(CGF, E, false, Dest, Ptr, Val1, Val2,
56539195062SYaxun Liu FailureOrder, Size, Order, Scope);
566cadbbe15STim Northover CGF.Builder.CreateBr(ContBB);
567cadbbe15STim Northover
568cadbbe15STim Northover CGF.Builder.SetInsertPoint(WeakBB);
569cadbbe15STim Northover emitAtomicCmpXchgFailureSet(CGF, E, true, Dest, Ptr, Val1, Val2,
57039195062SYaxun Liu FailureOrder, Size, Order, Scope);
571cadbbe15STim Northover CGF.Builder.CreateBr(ContBB);
572cadbbe15STim Northover
573cadbbe15STim Northover CGF.Builder.SetInsertPoint(ContBB);
574cadbbe15STim Northover }
575cadbbe15STim Northover return;
576cadbbe15STim Northover }
577fc207f2dSJohn McCall case AtomicExpr::AO__c11_atomic_load:
57839195062SYaxun Liu case AtomicExpr::AO__opencl_atomic_load:
579df0560caSAnshil Gandhi case AtomicExpr::AO__hip_atomic_load:
580fc207f2dSJohn McCall case AtomicExpr::AO__atomic_load_n:
581fc207f2dSJohn McCall case AtomicExpr::AO__atomic_load: {
582fc207f2dSJohn McCall llvm::LoadInst *Load = CGF.Builder.CreateLoad(Ptr);
58339195062SYaxun Liu Load->setAtomic(Order, Scope);
584fc207f2dSJohn McCall Load->setVolatile(E->isVolatile());
5857f416cc4SJohn McCall CGF.Builder.CreateStore(Load, Dest);
586fc207f2dSJohn McCall return;
587fc207f2dSJohn McCall }
588fc207f2dSJohn McCall
589fc207f2dSJohn McCall case AtomicExpr::AO__c11_atomic_store:
59039195062SYaxun Liu case AtomicExpr::AO__opencl_atomic_store:
591df0560caSAnshil Gandhi case AtomicExpr::AO__hip_atomic_store:
592fc207f2dSJohn McCall case AtomicExpr::AO__atomic_store:
593fc207f2dSJohn McCall case AtomicExpr::AO__atomic_store_n: {
5947f416cc4SJohn McCall llvm::Value *LoadVal1 = CGF.Builder.CreateLoad(Val1);
595fc207f2dSJohn McCall llvm::StoreInst *Store = CGF.Builder.CreateStore(LoadVal1, Ptr);
59639195062SYaxun Liu Store->setAtomic(Order, Scope);
597fc207f2dSJohn McCall Store->setVolatile(E->isVolatile());
598fc207f2dSJohn McCall return;
599fc207f2dSJohn McCall }
600fc207f2dSJohn McCall
601fc207f2dSJohn McCall case AtomicExpr::AO__c11_atomic_exchange:
602e13246a2SYaxun (Sam) Liu case AtomicExpr::AO__hip_atomic_exchange:
60339195062SYaxun Liu case AtomicExpr::AO__opencl_atomic_exchange:
604fc207f2dSJohn McCall case AtomicExpr::AO__atomic_exchange_n:
605fc207f2dSJohn McCall case AtomicExpr::AO__atomic_exchange:
606fc207f2dSJohn McCall Op = llvm::AtomicRMWInst::Xchg;
607fc207f2dSJohn McCall break;
608fc207f2dSJohn McCall
609fc207f2dSJohn McCall case AtomicExpr::AO__atomic_add_fetch:
61061d065e2SYaxun (Sam) Liu PostOp = E->getValueType()->isFloatingType() ? llvm::Instruction::FAdd
61161d065e2SYaxun (Sam) Liu : llvm::Instruction::Add;
612f3b3ccdaSAdrian Prantl LLVM_FALLTHROUGH;
613fc207f2dSJohn McCall case AtomicExpr::AO__c11_atomic_fetch_add:
614e13246a2SYaxun (Sam) Liu case AtomicExpr::AO__hip_atomic_fetch_add:
61539195062SYaxun Liu case AtomicExpr::AO__opencl_atomic_fetch_add:
616fc207f2dSJohn McCall case AtomicExpr::AO__atomic_fetch_add:
61761d065e2SYaxun (Sam) Liu Op = E->getValueType()->isFloatingType() ? llvm::AtomicRMWInst::FAdd
61861d065e2SYaxun (Sam) Liu : llvm::AtomicRMWInst::Add;
619fc207f2dSJohn McCall break;
620fc207f2dSJohn McCall
621fc207f2dSJohn McCall case AtomicExpr::AO__atomic_sub_fetch:
62261d065e2SYaxun (Sam) Liu PostOp = E->getValueType()->isFloatingType() ? llvm::Instruction::FSub
62361d065e2SYaxun (Sam) Liu : llvm::Instruction::Sub;
624f3b3ccdaSAdrian Prantl LLVM_FALLTHROUGH;
625fc207f2dSJohn McCall case AtomicExpr::AO__c11_atomic_fetch_sub:
62639195062SYaxun Liu case AtomicExpr::AO__opencl_atomic_fetch_sub:
627fc207f2dSJohn McCall case AtomicExpr::AO__atomic_fetch_sub:
62861d065e2SYaxun (Sam) Liu Op = E->getValueType()->isFloatingType() ? llvm::AtomicRMWInst::FSub
62961d065e2SYaxun (Sam) Liu : llvm::AtomicRMWInst::Sub;
630fc207f2dSJohn McCall break;
631fc207f2dSJohn McCall
6325cf58768STim Northover case AtomicExpr::AO__atomic_min_fetch:
6335cf58768STim Northover PostOpMinMax = true;
6345cf58768STim Northover LLVM_FALLTHROUGH;
6355cf58768STim Northover case AtomicExpr::AO__c11_atomic_fetch_min:
636e13246a2SYaxun (Sam) Liu case AtomicExpr::AO__hip_atomic_fetch_min:
63739195062SYaxun Liu case AtomicExpr::AO__opencl_atomic_fetch_min:
638d31327d5SElena Demikhovsky case AtomicExpr::AO__atomic_fetch_min:
63939195062SYaxun Liu Op = E->getValueType()->isSignedIntegerType() ? llvm::AtomicRMWInst::Min
64039195062SYaxun Liu : llvm::AtomicRMWInst::UMin;
64139195062SYaxun Liu break;
64239195062SYaxun Liu
6435cf58768STim Northover case AtomicExpr::AO__atomic_max_fetch:
6445cf58768STim Northover PostOpMinMax = true;
6455cf58768STim Northover LLVM_FALLTHROUGH;
6465cf58768STim Northover case AtomicExpr::AO__c11_atomic_fetch_max:
647e13246a2SYaxun (Sam) Liu case AtomicExpr::AO__hip_atomic_fetch_max:
64839195062SYaxun Liu case AtomicExpr::AO__opencl_atomic_fetch_max:
649d31327d5SElena Demikhovsky case AtomicExpr::AO__atomic_fetch_max:
65039195062SYaxun Liu Op = E->getValueType()->isSignedIntegerType() ? llvm::AtomicRMWInst::Max
65139195062SYaxun Liu : llvm::AtomicRMWInst::UMax;
65239195062SYaxun Liu break;
65339195062SYaxun Liu
654fc207f2dSJohn McCall case AtomicExpr::AO__atomic_and_fetch:
655fc207f2dSJohn McCall PostOp = llvm::Instruction::And;
656f3b3ccdaSAdrian Prantl LLVM_FALLTHROUGH;
657fc207f2dSJohn McCall case AtomicExpr::AO__c11_atomic_fetch_and:
658e13246a2SYaxun (Sam) Liu case AtomicExpr::AO__hip_atomic_fetch_and:
65939195062SYaxun Liu case AtomicExpr::AO__opencl_atomic_fetch_and:
660fc207f2dSJohn McCall case AtomicExpr::AO__atomic_fetch_and:
661fc207f2dSJohn McCall Op = llvm::AtomicRMWInst::And;
662fc207f2dSJohn McCall break;
663fc207f2dSJohn McCall
664fc207f2dSJohn McCall case AtomicExpr::AO__atomic_or_fetch:
665fc207f2dSJohn McCall PostOp = llvm::Instruction::Or;
666f3b3ccdaSAdrian Prantl LLVM_FALLTHROUGH;
667fc207f2dSJohn McCall case AtomicExpr::AO__c11_atomic_fetch_or:
668e13246a2SYaxun (Sam) Liu case AtomicExpr::AO__hip_atomic_fetch_or:
66939195062SYaxun Liu case AtomicExpr::AO__opencl_atomic_fetch_or:
670fc207f2dSJohn McCall case AtomicExpr::AO__atomic_fetch_or:
671fc207f2dSJohn McCall Op = llvm::AtomicRMWInst::Or;
672fc207f2dSJohn McCall break;
673fc207f2dSJohn McCall
674fc207f2dSJohn McCall case AtomicExpr::AO__atomic_xor_fetch:
675fc207f2dSJohn McCall PostOp = llvm::Instruction::Xor;
676f3b3ccdaSAdrian Prantl LLVM_FALLTHROUGH;
677fc207f2dSJohn McCall case AtomicExpr::AO__c11_atomic_fetch_xor:
678e13246a2SYaxun (Sam) Liu case AtomicExpr::AO__hip_atomic_fetch_xor:
67939195062SYaxun Liu case AtomicExpr::AO__opencl_atomic_fetch_xor:
680fc207f2dSJohn McCall case AtomicExpr::AO__atomic_fetch_xor:
681fc207f2dSJohn McCall Op = llvm::AtomicRMWInst::Xor;
682fc207f2dSJohn McCall break;
683fc207f2dSJohn McCall
684fc207f2dSJohn McCall case AtomicExpr::AO__atomic_nand_fetch:
6857aefb5b6SJames Y Knight PostOp = llvm::Instruction::And; // the NOT is special cased below
686f3b3ccdaSAdrian Prantl LLVM_FALLTHROUGH;
6876ea2431dSKai Luo case AtomicExpr::AO__c11_atomic_fetch_nand:
688fc207f2dSJohn McCall case AtomicExpr::AO__atomic_fetch_nand:
689fc207f2dSJohn McCall Op = llvm::AtomicRMWInst::Nand;
690fc207f2dSJohn McCall break;
691fc207f2dSJohn McCall }
692fc207f2dSJohn McCall
6937f416cc4SJohn McCall llvm::Value *LoadVal1 = CGF.Builder.CreateLoad(Val1);
694fc207f2dSJohn McCall llvm::AtomicRMWInst *RMWI =
69539195062SYaxun Liu CGF.Builder.CreateAtomicRMW(Op, Ptr.getPointer(), LoadVal1, Order, Scope);
696fc207f2dSJohn McCall RMWI->setVolatile(E->isVolatile());
697fc207f2dSJohn McCall
698fc207f2dSJohn McCall // For __atomic_*_fetch operations, perform the operation again to
699fc207f2dSJohn McCall // determine the value which was written.
700fc207f2dSJohn McCall llvm::Value *Result = RMWI;
7015cf58768STim Northover if (PostOpMinMax)
7025cf58768STim Northover Result = EmitPostAtomicMinMax(CGF.Builder, E->getOp(),
7035cf58768STim Northover E->getValueType()->isSignedIntegerType(),
7045cf58768STim Northover RMWI, LoadVal1);
7055cf58768STim Northover else if (PostOp)
7065cf58768STim Northover Result = CGF.Builder.CreateBinOp((llvm::Instruction::BinaryOps)PostOp, RMWI,
7075cf58768STim Northover LoadVal1);
708fc207f2dSJohn McCall if (E->getOp() == AtomicExpr::AO__atomic_nand_fetch)
709fc207f2dSJohn McCall Result = CGF.Builder.CreateNot(Result);
7107f416cc4SJohn McCall CGF.Builder.CreateStore(Result, Dest);
711fc207f2dSJohn McCall }
712fc207f2dSJohn McCall
713fc207f2dSJohn McCall // This function emits any expression (scalar, complex, or aggregate)
714fc207f2dSJohn McCall // into a temporary alloca.
7157f416cc4SJohn McCall static Address
EmitValToTemp(CodeGenFunction & CGF,Expr * E)716fc207f2dSJohn McCall EmitValToTemp(CodeGenFunction &CGF, Expr *E) {
7177f416cc4SJohn McCall Address DeclPtr = CGF.CreateMemTemp(E->getType(), ".atomictmp");
718fc207f2dSJohn McCall CGF.EmitAnyExprToMem(E, DeclPtr, E->getType().getQualifiers(),
719fc207f2dSJohn McCall /*Init*/ true);
720fc207f2dSJohn McCall return DeclPtr;
721fc207f2dSJohn McCall }
722fc207f2dSJohn McCall
EmitAtomicOp(CodeGenFunction & CGF,AtomicExpr * Expr,Address Dest,Address Ptr,Address Val1,Address Val2,llvm::Value * IsWeak,llvm::Value * FailureOrder,uint64_t Size,llvm::AtomicOrdering Order,llvm::Value * Scope)72330d652a4SYaxun Liu static void EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *Expr, Address Dest,
72430d652a4SYaxun Liu Address Ptr, Address Val1, Address Val2,
72530d652a4SYaxun Liu llvm::Value *IsWeak, llvm::Value *FailureOrder,
72630d652a4SYaxun Liu uint64_t Size, llvm::AtomicOrdering Order,
72730d652a4SYaxun Liu llvm::Value *Scope) {
72830d652a4SYaxun Liu auto ScopeModel = Expr->getScopeModel();
72930d652a4SYaxun Liu
73030d652a4SYaxun Liu // LLVM atomic instructions always have synch scope. If clang atomic
73130d652a4SYaxun Liu // expression has no scope operand, use default LLVM synch scope.
73230d652a4SYaxun Liu if (!ScopeModel) {
73330d652a4SYaxun Liu EmitAtomicOp(CGF, Expr, Dest, Ptr, Val1, Val2, IsWeak, FailureOrder, Size,
73430d652a4SYaxun Liu Order, CGF.CGM.getLLVMContext().getOrInsertSyncScopeID(""));
73530d652a4SYaxun Liu return;
73630d652a4SYaxun Liu }
73730d652a4SYaxun Liu
73830d652a4SYaxun Liu // Handle constant scope.
73930d652a4SYaxun Liu if (auto SC = dyn_cast<llvm::ConstantInt>(Scope)) {
74030d652a4SYaxun Liu auto SCID = CGF.getTargetHooks().getLLVMSyncScopeID(
741ec28a1dcSKonstantin Zhuravlyov CGF.CGM.getLangOpts(), ScopeModel->map(SC->getZExtValue()),
742ec28a1dcSKonstantin Zhuravlyov Order, CGF.CGM.getLLVMContext());
74330d652a4SYaxun Liu EmitAtomicOp(CGF, Expr, Dest, Ptr, Val1, Val2, IsWeak, FailureOrder, Size,
74430d652a4SYaxun Liu Order, SCID);
74530d652a4SYaxun Liu return;
74630d652a4SYaxun Liu }
74730d652a4SYaxun Liu
74830d652a4SYaxun Liu // Handle non-constant scope.
74930d652a4SYaxun Liu auto &Builder = CGF.Builder;
75030d652a4SYaxun Liu auto Scopes = ScopeModel->getRuntimeValues();
75130d652a4SYaxun Liu llvm::DenseMap<unsigned, llvm::BasicBlock *> BB;
75230d652a4SYaxun Liu for (auto S : Scopes)
75330d652a4SYaxun Liu BB[S] = CGF.createBasicBlock(getAsString(ScopeModel->map(S)), CGF.CurFn);
75430d652a4SYaxun Liu
75530d652a4SYaxun Liu llvm::BasicBlock *ContBB =
75630d652a4SYaxun Liu CGF.createBasicBlock("atomic.scope.continue", CGF.CurFn);
75730d652a4SYaxun Liu
75830d652a4SYaxun Liu auto *SC = Builder.CreateIntCast(Scope, Builder.getInt32Ty(), false);
75930d652a4SYaxun Liu // If unsupported synch scope is encountered at run time, assume a fallback
76030d652a4SYaxun Liu // synch scope value.
76130d652a4SYaxun Liu auto FallBack = ScopeModel->getFallBackValue();
76230d652a4SYaxun Liu llvm::SwitchInst *SI = Builder.CreateSwitch(SC, BB[FallBack]);
76330d652a4SYaxun Liu for (auto S : Scopes) {
76430d652a4SYaxun Liu auto *B = BB[S];
76530d652a4SYaxun Liu if (S != FallBack)
76630d652a4SYaxun Liu SI->addCase(Builder.getInt32(S), B);
76730d652a4SYaxun Liu
76830d652a4SYaxun Liu Builder.SetInsertPoint(B);
76930d652a4SYaxun Liu EmitAtomicOp(CGF, Expr, Dest, Ptr, Val1, Val2, IsWeak, FailureOrder, Size,
77030d652a4SYaxun Liu Order,
771ec28a1dcSKonstantin Zhuravlyov CGF.getTargetHooks().getLLVMSyncScopeID(CGF.CGM.getLangOpts(),
772ec28a1dcSKonstantin Zhuravlyov ScopeModel->map(S),
773ec28a1dcSKonstantin Zhuravlyov Order,
77430d652a4SYaxun Liu CGF.getLLVMContext()));
77530d652a4SYaxun Liu Builder.CreateBr(ContBB);
77630d652a4SYaxun Liu }
77730d652a4SYaxun Liu
77830d652a4SYaxun Liu Builder.SetInsertPoint(ContBB);
77930d652a4SYaxun Liu }
78030d652a4SYaxun Liu
781c7e82bd4SEd Schouten static void
AddDirectArgument(CodeGenFunction & CGF,CallArgList & Args,bool UseOptimizedLibcall,llvm::Value * Val,QualType ValTy,SourceLocation Loc,CharUnits SizeInChars)782c7e82bd4SEd Schouten AddDirectArgument(CodeGenFunction &CGF, CallArgList &Args,
7832d84e842SNick Lewycky bool UseOptimizedLibcall, llvm::Value *Val, QualType ValTy,
7840392cf89SDavid Majnemer SourceLocation Loc, CharUnits SizeInChars) {
785c7e82bd4SEd Schouten if (UseOptimizedLibcall) {
786c7e82bd4SEd Schouten // Load value and pass it to the function directly.
7877f416cc4SJohn McCall CharUnits Align = CGF.getContext().getTypeAlignInChars(ValTy);
7880392cf89SDavid Majnemer int64_t SizeInBits = CGF.getContext().toBits(SizeInChars);
7890392cf89SDavid Majnemer ValTy =
7900392cf89SDavid Majnemer CGF.getContext().getIntTypeForBitwidth(SizeInBits, /*Signed=*/false);
79150650766SNikita Popov llvm::Type *ITy = llvm::IntegerType::get(CGF.getLLVMContext(), SizeInBits);
79250650766SNikita Popov Address Ptr = Address(CGF.Builder.CreateBitCast(Val, ITy->getPointerTo()),
79350650766SNikita Popov ITy, Align);
7947f416cc4SJohn McCall Val = CGF.EmitLoadOfScalar(Ptr, false,
7957f416cc4SJohn McCall CGF.getContext().getPointerType(ValTy),
7960392cf89SDavid Majnemer Loc);
7970392cf89SDavid Majnemer // Coerce the value into an appropriately sized integer type.
798c7e82bd4SEd Schouten Args.add(RValue::get(Val), ValTy);
799c7e82bd4SEd Schouten } else {
800c7e82bd4SEd Schouten // Non-optimized functions always take a reference.
801c7e82bd4SEd Schouten Args.add(RValue::get(CGF.EmitCastToVoidPtr(Val)),
802c7e82bd4SEd Schouten CGF.getContext().VoidPtrTy);
803c7e82bd4SEd Schouten }
804c7e82bd4SEd Schouten }
805c7e82bd4SEd Schouten
EmitAtomicExpr(AtomicExpr * E)806cc2a6e06STim Northover RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) {
807fc207f2dSJohn McCall QualType AtomicTy = E->getPtr()->getType()->getPointeeType();
808fc207f2dSJohn McCall QualType MemTy = AtomicTy;
809fc207f2dSJohn McCall if (const AtomicType *AT = AtomicTy->getAs<AtomicType>())
810fc207f2dSJohn McCall MemTy = AT->getValueType();
8117f416cc4SJohn McCall llvm::Value *IsWeak = nullptr, *OrderFail = nullptr;
8127f416cc4SJohn McCall
8137f416cc4SJohn McCall Address Val1 = Address::invalid();
8147f416cc4SJohn McCall Address Val2 = Address::invalid();
815cc2a6e06STim Northover Address Dest = Address::invalid();
81601414bdcSWei Mi Address Ptr = EmitPointerWithAlignment(E->getPtr());
81701414bdcSWei Mi
8189dc1d0c7STim Northover if (E->getOp() == AtomicExpr::AO__c11_atomic_init ||
8199dc1d0c7STim Northover E->getOp() == AtomicExpr::AO__opencl_atomic_init) {
8209dc1d0c7STim Northover LValue lvalue = MakeAddrLValue(Ptr, AtomicTy);
8219dc1d0c7STim Northover EmitAtomicInit(E->getVal1(), lvalue);
8229dc1d0c7STim Northover return RValue::get(nullptr);
8239dc1d0c7STim Northover }
8249dc1d0c7STim Northover
825101309feSBevin Hansson auto TInfo = getContext().getTypeInfoInChars(AtomicTy);
826101309feSBevin Hansson uint64_t Size = TInfo.Width.getQuantity();
82701414bdcSWei Mi unsigned MaxInlineWidthInBits = getTarget().getMaxAtomicInlineWidth();
828fc207f2dSJohn McCall
829101309feSBevin Hansson bool Oversized = getContext().toBits(TInfo.Width) > MaxInlineWidthInBits;
830101309feSBevin Hansson bool Misaligned = (Ptr.getAlignment() % TInfo.Width) != 0;
831edb9fbb7SRichard Smith bool UseLibcall = Misaligned | Oversized;
83261d065e2SYaxun (Sam) Liu bool ShouldCastToIntPtrTy = true;
83361d065e2SYaxun (Sam) Liu
834e18c6ef6SThorsten Schuett CharUnits MaxInlineWidth =
835e18c6ef6SThorsten Schuett getContext().toCharUnitsFromBits(MaxInlineWidthInBits);
836edb9fbb7SRichard Smith
837e18c6ef6SThorsten Schuett DiagnosticsEngine &Diags = CGM.getDiags();
838e18c6ef6SThorsten Schuett
839e18c6ef6SThorsten Schuett if (Misaligned) {
840e18c6ef6SThorsten Schuett Diags.Report(E->getBeginLoc(), diag::warn_atomic_op_misaligned)
841101309feSBevin Hansson << (int)TInfo.Width.getQuantity()
842e18c6ef6SThorsten Schuett << (int)Ptr.getAlignment().getQuantity();
843e18c6ef6SThorsten Schuett }
844e18c6ef6SThorsten Schuett
845e18c6ef6SThorsten Schuett if (Oversized) {
846e18c6ef6SThorsten Schuett Diags.Report(E->getBeginLoc(), diag::warn_atomic_op_oversized)
847101309feSBevin Hansson << (int)TInfo.Width.getQuantity() << (int)MaxInlineWidth.getQuantity();
848edb9fbb7SRichard Smith }
849fc207f2dSJohn McCall
8508a13c418SCraig Topper llvm::Value *Order = EmitScalarExpr(E->getOrder());
85130d652a4SYaxun Liu llvm::Value *Scope =
85230d652a4SYaxun Liu E->getScopeModel() ? EmitScalarExpr(E->getScope()) : nullptr;
853fc207f2dSJohn McCall
854fc207f2dSJohn McCall switch (E->getOp()) {
855fc207f2dSJohn McCall case AtomicExpr::AO__c11_atomic_init:
85639195062SYaxun Liu case AtomicExpr::AO__opencl_atomic_init:
85781167fb7SJames Y Knight llvm_unreachable("Already handled above with EmitAtomicInit!");
858fc207f2dSJohn McCall
859fc207f2dSJohn McCall case AtomicExpr::AO__c11_atomic_load:
86039195062SYaxun Liu case AtomicExpr::AO__opencl_atomic_load:
861df0560caSAnshil Gandhi case AtomicExpr::AO__hip_atomic_load:
862fc207f2dSJohn McCall case AtomicExpr::AO__atomic_load_n:
863fc207f2dSJohn McCall break;
864fc207f2dSJohn McCall
865fc207f2dSJohn McCall case AtomicExpr::AO__atomic_load:
8667f416cc4SJohn McCall Dest = EmitPointerWithAlignment(E->getVal1());
867fc207f2dSJohn McCall break;
868fc207f2dSJohn McCall
869fc207f2dSJohn McCall case AtomicExpr::AO__atomic_store:
8707f416cc4SJohn McCall Val1 = EmitPointerWithAlignment(E->getVal1());
871fc207f2dSJohn McCall break;
872fc207f2dSJohn McCall
873fc207f2dSJohn McCall case AtomicExpr::AO__atomic_exchange:
8747f416cc4SJohn McCall Val1 = EmitPointerWithAlignment(E->getVal1());
8757f416cc4SJohn McCall Dest = EmitPointerWithAlignment(E->getVal2());
876fc207f2dSJohn McCall break;
877fc207f2dSJohn McCall
878fc207f2dSJohn McCall case AtomicExpr::AO__c11_atomic_compare_exchange_strong:
879fc207f2dSJohn McCall case AtomicExpr::AO__c11_atomic_compare_exchange_weak:
88039195062SYaxun Liu case AtomicExpr::AO__opencl_atomic_compare_exchange_strong:
881e13246a2SYaxun (Sam) Liu case AtomicExpr::AO__hip_atomic_compare_exchange_strong:
88239195062SYaxun Liu case AtomicExpr::AO__opencl_atomic_compare_exchange_weak:
883df0560caSAnshil Gandhi case AtomicExpr::AO__hip_atomic_compare_exchange_weak:
884fc207f2dSJohn McCall case AtomicExpr::AO__atomic_compare_exchange_n:
885fc207f2dSJohn McCall case AtomicExpr::AO__atomic_compare_exchange:
8867f416cc4SJohn McCall Val1 = EmitPointerWithAlignment(E->getVal1());
887fc207f2dSJohn McCall if (E->getOp() == AtomicExpr::AO__atomic_compare_exchange)
8887f416cc4SJohn McCall Val2 = EmitPointerWithAlignment(E->getVal2());
889fc207f2dSJohn McCall else
890fc207f2dSJohn McCall Val2 = EmitValToTemp(*this, E->getVal2());
891fc207f2dSJohn McCall OrderFail = EmitScalarExpr(E->getOrderFail());
89239195062SYaxun Liu if (E->getOp() == AtomicExpr::AO__atomic_compare_exchange_n ||
89339195062SYaxun Liu E->getOp() == AtomicExpr::AO__atomic_compare_exchange)
894cadbbe15STim Northover IsWeak = EmitScalarExpr(E->getWeak());
895fc207f2dSJohn McCall break;
896fc207f2dSJohn McCall
897fc207f2dSJohn McCall case AtomicExpr::AO__c11_atomic_fetch_add:
898fc207f2dSJohn McCall case AtomicExpr::AO__c11_atomic_fetch_sub:
899e13246a2SYaxun (Sam) Liu case AtomicExpr::AO__hip_atomic_fetch_add:
90039195062SYaxun Liu case AtomicExpr::AO__opencl_atomic_fetch_add:
90139195062SYaxun Liu case AtomicExpr::AO__opencl_atomic_fetch_sub:
902fc207f2dSJohn McCall if (MemTy->isPointerType()) {
903fc207f2dSJohn McCall // For pointer arithmetic, we're required to do a bit of math:
904fc207f2dSJohn McCall // adding 1 to an int* is not the same as adding 1 to a uintptr_t.
905fc207f2dSJohn McCall // ... but only for the C11 builtins. The GNU builtins expect the
906fc207f2dSJohn McCall // user to multiply by sizeof(T).
907fc207f2dSJohn McCall QualType Val1Ty = E->getVal1()->getType();
908fc207f2dSJohn McCall llvm::Value *Val1Scalar = EmitScalarExpr(E->getVal1());
909fc207f2dSJohn McCall CharUnits PointeeIncAmt =
910fc207f2dSJohn McCall getContext().getTypeSizeInChars(MemTy->getPointeeType());
911fc207f2dSJohn McCall Val1Scalar = Builder.CreateMul(Val1Scalar, CGM.getSize(PointeeIncAmt));
9127f416cc4SJohn McCall auto Temp = CreateMemTemp(Val1Ty, ".atomictmp");
9137f416cc4SJohn McCall Val1 = Temp;
9147f416cc4SJohn McCall EmitStoreOfScalar(Val1Scalar, MakeAddrLValue(Temp, Val1Ty));
915fc207f2dSJohn McCall break;
916fc207f2dSJohn McCall }
917f3b3ccdaSAdrian Prantl LLVM_FALLTHROUGH;
918fc207f2dSJohn McCall case AtomicExpr::AO__atomic_fetch_add:
919fc207f2dSJohn McCall case AtomicExpr::AO__atomic_fetch_sub:
920fc207f2dSJohn McCall case AtomicExpr::AO__atomic_add_fetch:
921fc207f2dSJohn McCall case AtomicExpr::AO__atomic_sub_fetch:
92261d065e2SYaxun (Sam) Liu ShouldCastToIntPtrTy = !MemTy->isFloatingType();
92361d065e2SYaxun (Sam) Liu LLVM_FALLTHROUGH;
92461d065e2SYaxun (Sam) Liu
925fc207f2dSJohn McCall case AtomicExpr::AO__c11_atomic_store:
926fc207f2dSJohn McCall case AtomicExpr::AO__c11_atomic_exchange:
92739195062SYaxun Liu case AtomicExpr::AO__opencl_atomic_store:
928df0560caSAnshil Gandhi case AtomicExpr::AO__hip_atomic_store:
92939195062SYaxun Liu case AtomicExpr::AO__opencl_atomic_exchange:
930e13246a2SYaxun (Sam) Liu case AtomicExpr::AO__hip_atomic_exchange:
931fc207f2dSJohn McCall case AtomicExpr::AO__atomic_store_n:
932fc207f2dSJohn McCall case AtomicExpr::AO__atomic_exchange_n:
933fc207f2dSJohn McCall case AtomicExpr::AO__c11_atomic_fetch_and:
934fc207f2dSJohn McCall case AtomicExpr::AO__c11_atomic_fetch_or:
935fc207f2dSJohn McCall case AtomicExpr::AO__c11_atomic_fetch_xor:
9366ea2431dSKai Luo case AtomicExpr::AO__c11_atomic_fetch_nand:
9375cf58768STim Northover case AtomicExpr::AO__c11_atomic_fetch_max:
9385cf58768STim Northover case AtomicExpr::AO__c11_atomic_fetch_min:
93939195062SYaxun Liu case AtomicExpr::AO__opencl_atomic_fetch_and:
94039195062SYaxun Liu case AtomicExpr::AO__opencl_atomic_fetch_or:
94139195062SYaxun Liu case AtomicExpr::AO__opencl_atomic_fetch_xor:
94239195062SYaxun Liu case AtomicExpr::AO__opencl_atomic_fetch_min:
94339195062SYaxun Liu case AtomicExpr::AO__opencl_atomic_fetch_max:
944fc207f2dSJohn McCall case AtomicExpr::AO__atomic_fetch_and:
945e13246a2SYaxun (Sam) Liu case AtomicExpr::AO__hip_atomic_fetch_and:
946fc207f2dSJohn McCall case AtomicExpr::AO__atomic_fetch_or:
947e13246a2SYaxun (Sam) Liu case AtomicExpr::AO__hip_atomic_fetch_or:
948fc207f2dSJohn McCall case AtomicExpr::AO__atomic_fetch_xor:
949e13246a2SYaxun (Sam) Liu case AtomicExpr::AO__hip_atomic_fetch_xor:
950fc207f2dSJohn McCall case AtomicExpr::AO__atomic_fetch_nand:
951fc207f2dSJohn McCall case AtomicExpr::AO__atomic_and_fetch:
952fc207f2dSJohn McCall case AtomicExpr::AO__atomic_or_fetch:
953fc207f2dSJohn McCall case AtomicExpr::AO__atomic_xor_fetch:
954fc207f2dSJohn McCall case AtomicExpr::AO__atomic_nand_fetch:
9555cf58768STim Northover case AtomicExpr::AO__atomic_max_fetch:
9565cf58768STim Northover case AtomicExpr::AO__atomic_min_fetch:
957d31327d5SElena Demikhovsky case AtomicExpr::AO__atomic_fetch_max:
958e13246a2SYaxun (Sam) Liu case AtomicExpr::AO__hip_atomic_fetch_max:
9595cf58768STim Northover case AtomicExpr::AO__atomic_fetch_min:
960e13246a2SYaxun (Sam) Liu case AtomicExpr::AO__hip_atomic_fetch_min:
961fc207f2dSJohn McCall Val1 = EmitValToTemp(*this, E->getVal1());
962fc207f2dSJohn McCall break;
963fc207f2dSJohn McCall }
964fc207f2dSJohn McCall
965ee8d04d8SDavid Majnemer QualType RValTy = E->getType().getUnqualifiedType();
966ee8d04d8SDavid Majnemer
967cc2a6e06STim Northover // The inlined atomics only function on iN types, where N is a power of 2. We
968cc2a6e06STim Northover // need to make sure (via temporaries if necessary) that all incoming values
969cc2a6e06STim Northover // are compatible.
970cc2a6e06STim Northover LValue AtomicVal = MakeAddrLValue(Ptr, AtomicTy);
971cc2a6e06STim Northover AtomicInfo Atomics(*this, AtomicVal);
972cc2a6e06STim Northover
97361d065e2SYaxun (Sam) Liu if (ShouldCastToIntPtrTy) {
974cc2a6e06STim Northover Ptr = Atomics.emitCastToAtomicIntPointer(Ptr);
97561d065e2SYaxun (Sam) Liu if (Val1.isValid())
97661d065e2SYaxun (Sam) Liu Val1 = Atomics.convertToAtomicIntPointer(Val1);
97761d065e2SYaxun (Sam) Liu if (Val2.isValid())
97861d065e2SYaxun (Sam) Liu Val2 = Atomics.convertToAtomicIntPointer(Val2);
97961d065e2SYaxun (Sam) Liu }
98061d065e2SYaxun (Sam) Liu if (Dest.isValid()) {
98161d065e2SYaxun (Sam) Liu if (ShouldCastToIntPtrTy)
982cc2a6e06STim Northover Dest = Atomics.emitCastToAtomicIntPointer(Dest);
98361d065e2SYaxun (Sam) Liu } else if (E->isCmpXChg())
984cc2a6e06STim Northover Dest = CreateMemTemp(RValTy, "cmpxchg.bool");
98561d065e2SYaxun (Sam) Liu else if (!RValTy->isVoidType()) {
98661d065e2SYaxun (Sam) Liu Dest = Atomics.CreateTempAlloca();
98761d065e2SYaxun (Sam) Liu if (ShouldCastToIntPtrTy)
98861d065e2SYaxun (Sam) Liu Dest = Atomics.emitCastToAtomicIntPointer(Dest);
98961d065e2SYaxun (Sam) Liu }
990fc207f2dSJohn McCall
991fc207f2dSJohn McCall // Use a library call. See: http://gcc.gnu.org/wiki/Atomic/GCCMM/LIbrary .
992fc207f2dSJohn McCall if (UseLibcall) {
993c7e82bd4SEd Schouten bool UseOptimizedLibcall = false;
994c7e82bd4SEd Schouten switch (E->getOp()) {
99581167fb7SJames Y Knight case AtomicExpr::AO__c11_atomic_init:
99639195062SYaxun Liu case AtomicExpr::AO__opencl_atomic_init:
99781167fb7SJames Y Knight llvm_unreachable("Already handled above with EmitAtomicInit!");
99881167fb7SJames Y Knight
999c7e82bd4SEd Schouten case AtomicExpr::AO__c11_atomic_fetch_add:
100039195062SYaxun Liu case AtomicExpr::AO__opencl_atomic_fetch_add:
1001c7e82bd4SEd Schouten case AtomicExpr::AO__atomic_fetch_add:
1002e13246a2SYaxun (Sam) Liu case AtomicExpr::AO__hip_atomic_fetch_add:
1003c7e82bd4SEd Schouten case AtomicExpr::AO__c11_atomic_fetch_and:
100439195062SYaxun Liu case AtomicExpr::AO__opencl_atomic_fetch_and:
1005e13246a2SYaxun (Sam) Liu case AtomicExpr::AO__hip_atomic_fetch_and:
1006c7e82bd4SEd Schouten case AtomicExpr::AO__atomic_fetch_and:
1007c7e82bd4SEd Schouten case AtomicExpr::AO__c11_atomic_fetch_or:
100839195062SYaxun Liu case AtomicExpr::AO__opencl_atomic_fetch_or:
1009e13246a2SYaxun (Sam) Liu case AtomicExpr::AO__hip_atomic_fetch_or:
1010c7e82bd4SEd Schouten case AtomicExpr::AO__atomic_fetch_or:
10116ea2431dSKai Luo case AtomicExpr::AO__c11_atomic_fetch_nand:
101281167fb7SJames Y Knight case AtomicExpr::AO__atomic_fetch_nand:
1013c7e82bd4SEd Schouten case AtomicExpr::AO__c11_atomic_fetch_sub:
101439195062SYaxun Liu case AtomicExpr::AO__opencl_atomic_fetch_sub:
1015c7e82bd4SEd Schouten case AtomicExpr::AO__atomic_fetch_sub:
1016c7e82bd4SEd Schouten case AtomicExpr::AO__c11_atomic_fetch_xor:
101739195062SYaxun Liu case AtomicExpr::AO__opencl_atomic_fetch_xor:
101839195062SYaxun Liu case AtomicExpr::AO__opencl_atomic_fetch_min:
101939195062SYaxun Liu case AtomicExpr::AO__opencl_atomic_fetch_max:
1020c7e82bd4SEd Schouten case AtomicExpr::AO__atomic_fetch_xor:
1021e13246a2SYaxun (Sam) Liu case AtomicExpr::AO__hip_atomic_fetch_xor:
10225cf58768STim Northover case AtomicExpr::AO__c11_atomic_fetch_max:
10235cf58768STim Northover case AtomicExpr::AO__c11_atomic_fetch_min:
102481167fb7SJames Y Knight case AtomicExpr::AO__atomic_add_fetch:
102581167fb7SJames Y Knight case AtomicExpr::AO__atomic_and_fetch:
102681167fb7SJames Y Knight case AtomicExpr::AO__atomic_nand_fetch:
102781167fb7SJames Y Knight case AtomicExpr::AO__atomic_or_fetch:
102881167fb7SJames Y Knight case AtomicExpr::AO__atomic_sub_fetch:
102981167fb7SJames Y Knight case AtomicExpr::AO__atomic_xor_fetch:
1030d31327d5SElena Demikhovsky case AtomicExpr::AO__atomic_fetch_max:
1031e13246a2SYaxun (Sam) Liu case AtomicExpr::AO__hip_atomic_fetch_max:
10325cf58768STim Northover case AtomicExpr::AO__atomic_fetch_min:
1033e13246a2SYaxun (Sam) Liu case AtomicExpr::AO__hip_atomic_fetch_min:
10345cf58768STim Northover case AtomicExpr::AO__atomic_max_fetch:
10355cf58768STim Northover case AtomicExpr::AO__atomic_min_fetch:
1036c7e82bd4SEd Schouten // For these, only library calls for certain sizes exist.
1037c7e82bd4SEd Schouten UseOptimizedLibcall = true;
1038c7e82bd4SEd Schouten break;
103981167fb7SJames Y Knight
1040da3729d1SRichard Smith case AtomicExpr::AO__atomic_load:
1041da3729d1SRichard Smith case AtomicExpr::AO__atomic_store:
1042da3729d1SRichard Smith case AtomicExpr::AO__atomic_exchange:
1043da3729d1SRichard Smith case AtomicExpr::AO__atomic_compare_exchange:
1044da3729d1SRichard Smith // Use the generic version if we don't know that the operand will be
1045da3729d1SRichard Smith // suitably aligned for the optimized version.
1046da3729d1SRichard Smith if (Misaligned)
1047da3729d1SRichard Smith break;
1048da3729d1SRichard Smith LLVM_FALLTHROUGH;
104981167fb7SJames Y Knight case AtomicExpr::AO__c11_atomic_load:
105081167fb7SJames Y Knight case AtomicExpr::AO__c11_atomic_store:
105181167fb7SJames Y Knight case AtomicExpr::AO__c11_atomic_exchange:
105281167fb7SJames Y Knight case AtomicExpr::AO__c11_atomic_compare_exchange_weak:
105381167fb7SJames Y Knight case AtomicExpr::AO__c11_atomic_compare_exchange_strong:
1054e13246a2SYaxun (Sam) Liu case AtomicExpr::AO__hip_atomic_compare_exchange_strong:
105539195062SYaxun Liu case AtomicExpr::AO__opencl_atomic_load:
1056df0560caSAnshil Gandhi case AtomicExpr::AO__hip_atomic_load:
105739195062SYaxun Liu case AtomicExpr::AO__opencl_atomic_store:
1058df0560caSAnshil Gandhi case AtomicExpr::AO__hip_atomic_store:
105939195062SYaxun Liu case AtomicExpr::AO__opencl_atomic_exchange:
1060e13246a2SYaxun (Sam) Liu case AtomicExpr::AO__hip_atomic_exchange:
106139195062SYaxun Liu case AtomicExpr::AO__opencl_atomic_compare_exchange_weak:
1062df0560caSAnshil Gandhi case AtomicExpr::AO__hip_atomic_compare_exchange_weak:
106339195062SYaxun Liu case AtomicExpr::AO__opencl_atomic_compare_exchange_strong:
106481167fb7SJames Y Knight case AtomicExpr::AO__atomic_load_n:
106581167fb7SJames Y Knight case AtomicExpr::AO__atomic_store_n:
106681167fb7SJames Y Knight case AtomicExpr::AO__atomic_exchange_n:
106781167fb7SJames Y Knight case AtomicExpr::AO__atomic_compare_exchange_n:
1068c7e82bd4SEd Schouten // Only use optimized library calls for sizes for which they exist.
1069da3729d1SRichard Smith // FIXME: Size == 16 optimized library functions exist too.
1070c7e82bd4SEd Schouten if (Size == 1 || Size == 2 || Size == 4 || Size == 8)
1071c7e82bd4SEd Schouten UseOptimizedLibcall = true;
1072c7e82bd4SEd Schouten break;
1073c7e82bd4SEd Schouten }
1074fc207f2dSJohn McCall
1075fc207f2dSJohn McCall CallArgList Args;
1076c7e82bd4SEd Schouten if (!UseOptimizedLibcall) {
1077c7e82bd4SEd Schouten // For non-optimized library calls, the size is the first parameter
1078fc207f2dSJohn McCall Args.add(RValue::get(llvm::ConstantInt::get(SizeTy, Size)),
1079fc207f2dSJohn McCall getContext().getSizeType());
1080c7e82bd4SEd Schouten }
1081c7e82bd4SEd Schouten // Atomic address is the first or second parameter
108239195062SYaxun Liu // The OpenCL atomic library functions only accept pointer arguments to
108339195062SYaxun Liu // generic address space.
108439195062SYaxun Liu auto CastToGenericAddrSpace = [&](llvm::Value *V, QualType PT) {
108539195062SYaxun Liu if (!E->isOpenCL())
108639195062SYaxun Liu return V;
10877e38f0c4SSimon Pilgrim auto AS = PT->castAs<PointerType>()->getPointeeType().getAddressSpace();
108839195062SYaxun Liu if (AS == LangAS::opencl_generic)
108939195062SYaxun Liu return V;
109039195062SYaxun Liu auto DestAS = getContext().getTargetAddressSpace(LangAS::opencl_generic);
1091b4f46555SNikita Popov auto T = llvm::cast<llvm::PointerType>(V->getType());
1092b4f46555SNikita Popov auto *DestType = llvm::PointerType::getWithSamePointeeType(T, DestAS);
109339195062SYaxun Liu
109439195062SYaxun Liu return getTargetHooks().performAddrSpaceCast(
109539195062SYaxun Liu *this, V, AS, LangAS::opencl_generic, DestType, false);
109639195062SYaxun Liu };
109739195062SYaxun Liu
109839195062SYaxun Liu Args.add(RValue::get(CastToGenericAddrSpace(
109939195062SYaxun Liu EmitCastToVoidPtr(Ptr.getPointer()), E->getPtr()->getType())),
11007f416cc4SJohn McCall getContext().VoidPtrTy);
1101fc207f2dSJohn McCall
1102c7e82bd4SEd Schouten std::string LibCallName;
110374798a34SLogan Chien QualType LoweredMemTy =
110474798a34SLogan Chien MemTy->isPointerType() ? getContext().getIntPtrType() : MemTy;
1105c7e82bd4SEd Schouten QualType RetTy;
1106c7e82bd4SEd Schouten bool HaveRetTy = false;
11077aefb5b6SJames Y Knight llvm::Instruction::BinaryOps PostOp = (llvm::Instruction::BinaryOps)0;
11085cf58768STim Northover bool PostOpMinMax = false;
1109fc207f2dSJohn McCall switch (E->getOp()) {
111081167fb7SJames Y Knight case AtomicExpr::AO__c11_atomic_init:
111139195062SYaxun Liu case AtomicExpr::AO__opencl_atomic_init:
111281167fb7SJames Y Knight llvm_unreachable("Already handled!");
111381167fb7SJames Y Knight
1114fc207f2dSJohn McCall // There is only one libcall for compare an exchange, because there is no
1115fc207f2dSJohn McCall // optimisation benefit possible from a libcall version of a weak compare
1116fc207f2dSJohn McCall // and exchange.
1117c7e82bd4SEd Schouten // bool __atomic_compare_exchange(size_t size, void *mem, void *expected,
1118fc207f2dSJohn McCall // void *desired, int success, int failure)
1119c7e82bd4SEd Schouten // bool __atomic_compare_exchange_N(T *mem, T *expected, T desired,
1120c7e82bd4SEd Schouten // int success, int failure)
1121fc207f2dSJohn McCall case AtomicExpr::AO__c11_atomic_compare_exchange_weak:
1122fc207f2dSJohn McCall case AtomicExpr::AO__c11_atomic_compare_exchange_strong:
112339195062SYaxun Liu case AtomicExpr::AO__opencl_atomic_compare_exchange_weak:
1124df0560caSAnshil Gandhi case AtomicExpr::AO__hip_atomic_compare_exchange_weak:
112539195062SYaxun Liu case AtomicExpr::AO__opencl_atomic_compare_exchange_strong:
1126e13246a2SYaxun (Sam) Liu case AtomicExpr::AO__hip_atomic_compare_exchange_strong:
1127fc207f2dSJohn McCall case AtomicExpr::AO__atomic_compare_exchange:
1128fc207f2dSJohn McCall case AtomicExpr::AO__atomic_compare_exchange_n:
1129fc207f2dSJohn McCall LibCallName = "__atomic_compare_exchange";
1130fc207f2dSJohn McCall RetTy = getContext().BoolTy;
1131c7e82bd4SEd Schouten HaveRetTy = true;
113239195062SYaxun Liu Args.add(
113339195062SYaxun Liu RValue::get(CastToGenericAddrSpace(
113439195062SYaxun Liu EmitCastToVoidPtr(Val1.getPointer()), E->getVal1()->getType())),
11357f416cc4SJohn McCall getContext().VoidPtrTy);
11367f416cc4SJohn McCall AddDirectArgument(*this, Args, UseOptimizedLibcall, Val2.getPointer(),
1137101309feSBevin Hansson MemTy, E->getExprLoc(), TInfo.Width);
11385fa40c3bSNick Lewycky Args.add(RValue::get(Order), getContext().IntTy);
1139fc207f2dSJohn McCall Order = OrderFail;
1140fc207f2dSJohn McCall break;
1141fc207f2dSJohn McCall // void __atomic_exchange(size_t size, void *mem, void *val, void *return,
1142fc207f2dSJohn McCall // int order)
1143c7e82bd4SEd Schouten // T __atomic_exchange_N(T *mem, T val, int order)
1144fc207f2dSJohn McCall case AtomicExpr::AO__c11_atomic_exchange:
114539195062SYaxun Liu case AtomicExpr::AO__opencl_atomic_exchange:
1146fc207f2dSJohn McCall case AtomicExpr::AO__atomic_exchange_n:
1147fc207f2dSJohn McCall case AtomicExpr::AO__atomic_exchange:
1148e13246a2SYaxun (Sam) Liu case AtomicExpr::AO__hip_atomic_exchange:
1149fc207f2dSJohn McCall LibCallName = "__atomic_exchange";
11507f416cc4SJohn McCall AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1.getPointer(),
1151101309feSBevin Hansson MemTy, E->getExprLoc(), TInfo.Width);
1152fc207f2dSJohn McCall break;
1153fc207f2dSJohn McCall // void __atomic_store(size_t size, void *mem, void *val, int order)
1154c7e82bd4SEd Schouten // void __atomic_store_N(T *mem, T val, int order)
1155fc207f2dSJohn McCall case AtomicExpr::AO__c11_atomic_store:
115639195062SYaxun Liu case AtomicExpr::AO__opencl_atomic_store:
1157df0560caSAnshil Gandhi case AtomicExpr::AO__hip_atomic_store:
1158fc207f2dSJohn McCall case AtomicExpr::AO__atomic_store:
1159fc207f2dSJohn McCall case AtomicExpr::AO__atomic_store_n:
1160fc207f2dSJohn McCall LibCallName = "__atomic_store";
1161c7e82bd4SEd Schouten RetTy = getContext().VoidTy;
1162c7e82bd4SEd Schouten HaveRetTy = true;
11637f416cc4SJohn McCall AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1.getPointer(),
1164101309feSBevin Hansson MemTy, E->getExprLoc(), TInfo.Width);
1165fc207f2dSJohn McCall break;
1166fc207f2dSJohn McCall // void __atomic_load(size_t size, void *mem, void *return, int order)
1167c7e82bd4SEd Schouten // T __atomic_load_N(T *mem, int order)
1168fc207f2dSJohn McCall case AtomicExpr::AO__c11_atomic_load:
116939195062SYaxun Liu case AtomicExpr::AO__opencl_atomic_load:
1170df0560caSAnshil Gandhi case AtomicExpr::AO__hip_atomic_load:
1171fc207f2dSJohn McCall case AtomicExpr::AO__atomic_load:
1172fc207f2dSJohn McCall case AtomicExpr::AO__atomic_load_n:
1173fc207f2dSJohn McCall LibCallName = "__atomic_load";
1174c7e82bd4SEd Schouten break;
11757aefb5b6SJames Y Knight // T __atomic_add_fetch_N(T *mem, T val, int order)
1176c7e82bd4SEd Schouten // T __atomic_fetch_add_N(T *mem, T val, int order)
11777aefb5b6SJames Y Knight case AtomicExpr::AO__atomic_add_fetch:
11787aefb5b6SJames Y Knight PostOp = llvm::Instruction::Add;
1179f3b3ccdaSAdrian Prantl LLVM_FALLTHROUGH;
1180c7e82bd4SEd Schouten case AtomicExpr::AO__c11_atomic_fetch_add:
118139195062SYaxun Liu case AtomicExpr::AO__opencl_atomic_fetch_add:
1182c7e82bd4SEd Schouten case AtomicExpr::AO__atomic_fetch_add:
1183e13246a2SYaxun (Sam) Liu case AtomicExpr::AO__hip_atomic_fetch_add:
1184c7e82bd4SEd Schouten LibCallName = "__atomic_fetch_add";
11857f416cc4SJohn McCall AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1.getPointer(),
1186101309feSBevin Hansson LoweredMemTy, E->getExprLoc(), TInfo.Width);
1187c7e82bd4SEd Schouten break;
11887aefb5b6SJames Y Knight // T __atomic_and_fetch_N(T *mem, T val, int order)
1189c7e82bd4SEd Schouten // T __atomic_fetch_and_N(T *mem, T val, int order)
11907aefb5b6SJames Y Knight case AtomicExpr::AO__atomic_and_fetch:
11917aefb5b6SJames Y Knight PostOp = llvm::Instruction::And;
1192f3b3ccdaSAdrian Prantl LLVM_FALLTHROUGH;
1193c7e82bd4SEd Schouten case AtomicExpr::AO__c11_atomic_fetch_and:
119439195062SYaxun Liu case AtomicExpr::AO__opencl_atomic_fetch_and:
1195e13246a2SYaxun (Sam) Liu case AtomicExpr::AO__hip_atomic_fetch_and:
1196c7e82bd4SEd Schouten case AtomicExpr::AO__atomic_fetch_and:
1197c7e82bd4SEd Schouten LibCallName = "__atomic_fetch_and";
11987f416cc4SJohn McCall AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1.getPointer(),
1199101309feSBevin Hansson MemTy, E->getExprLoc(), TInfo.Width);
1200c7e82bd4SEd Schouten break;
12017aefb5b6SJames Y Knight // T __atomic_or_fetch_N(T *mem, T val, int order)
1202c7e82bd4SEd Schouten // T __atomic_fetch_or_N(T *mem, T val, int order)
12037aefb5b6SJames Y Knight case AtomicExpr::AO__atomic_or_fetch:
12047aefb5b6SJames Y Knight PostOp = llvm::Instruction::Or;
1205f3b3ccdaSAdrian Prantl LLVM_FALLTHROUGH;
1206c7e82bd4SEd Schouten case AtomicExpr::AO__c11_atomic_fetch_or:
120739195062SYaxun Liu case AtomicExpr::AO__opencl_atomic_fetch_or:
1208e13246a2SYaxun (Sam) Liu case AtomicExpr::AO__hip_atomic_fetch_or:
1209c7e82bd4SEd Schouten case AtomicExpr::AO__atomic_fetch_or:
1210c7e82bd4SEd Schouten LibCallName = "__atomic_fetch_or";
12117f416cc4SJohn McCall AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1.getPointer(),
1212101309feSBevin Hansson MemTy, E->getExprLoc(), TInfo.Width);
1213c7e82bd4SEd Schouten break;
12147aefb5b6SJames Y Knight // T __atomic_sub_fetch_N(T *mem, T val, int order)
1215c7e82bd4SEd Schouten // T __atomic_fetch_sub_N(T *mem, T val, int order)
12167aefb5b6SJames Y Knight case AtomicExpr::AO__atomic_sub_fetch:
12177aefb5b6SJames Y Knight PostOp = llvm::Instruction::Sub;
1218f3b3ccdaSAdrian Prantl LLVM_FALLTHROUGH;
1219c7e82bd4SEd Schouten case AtomicExpr::AO__c11_atomic_fetch_sub:
122039195062SYaxun Liu case AtomicExpr::AO__opencl_atomic_fetch_sub:
1221c7e82bd4SEd Schouten case AtomicExpr::AO__atomic_fetch_sub:
1222c7e82bd4SEd Schouten LibCallName = "__atomic_fetch_sub";
12237f416cc4SJohn McCall AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1.getPointer(),
1224101309feSBevin Hansson LoweredMemTy, E->getExprLoc(), TInfo.Width);
1225c7e82bd4SEd Schouten break;
12267aefb5b6SJames Y Knight // T __atomic_xor_fetch_N(T *mem, T val, int order)
1227c7e82bd4SEd Schouten // T __atomic_fetch_xor_N(T *mem, T val, int order)
12287aefb5b6SJames Y Knight case AtomicExpr::AO__atomic_xor_fetch:
12297aefb5b6SJames Y Knight PostOp = llvm::Instruction::Xor;
1230f3b3ccdaSAdrian Prantl LLVM_FALLTHROUGH;
1231c7e82bd4SEd Schouten case AtomicExpr::AO__c11_atomic_fetch_xor:
123239195062SYaxun Liu case AtomicExpr::AO__opencl_atomic_fetch_xor:
1233e13246a2SYaxun (Sam) Liu case AtomicExpr::AO__hip_atomic_fetch_xor:
1234c7e82bd4SEd Schouten case AtomicExpr::AO__atomic_fetch_xor:
1235c7e82bd4SEd Schouten LibCallName = "__atomic_fetch_xor";
12367f416cc4SJohn McCall AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1.getPointer(),
1237101309feSBevin Hansson MemTy, E->getExprLoc(), TInfo.Width);
1238fc207f2dSJohn McCall break;
12395cf58768STim Northover case AtomicExpr::AO__atomic_min_fetch:
12405cf58768STim Northover PostOpMinMax = true;
12415cf58768STim Northover LLVM_FALLTHROUGH;
12425cf58768STim Northover case AtomicExpr::AO__c11_atomic_fetch_min:
1243d31327d5SElena Demikhovsky case AtomicExpr::AO__atomic_fetch_min:
1244e13246a2SYaxun (Sam) Liu case AtomicExpr::AO__hip_atomic_fetch_min:
124539195062SYaxun Liu case AtomicExpr::AO__opencl_atomic_fetch_min:
124639195062SYaxun Liu LibCallName = E->getValueType()->isSignedIntegerType()
124739195062SYaxun Liu ? "__atomic_fetch_min"
124839195062SYaxun Liu : "__atomic_fetch_umin";
124939195062SYaxun Liu AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1.getPointer(),
1250101309feSBevin Hansson LoweredMemTy, E->getExprLoc(), TInfo.Width);
125139195062SYaxun Liu break;
12525cf58768STim Northover case AtomicExpr::AO__atomic_max_fetch:
12535cf58768STim Northover PostOpMinMax = true;
12545cf58768STim Northover LLVM_FALLTHROUGH;
12555cf58768STim Northover case AtomicExpr::AO__c11_atomic_fetch_max:
1256d31327d5SElena Demikhovsky case AtomicExpr::AO__atomic_fetch_max:
1257e13246a2SYaxun (Sam) Liu case AtomicExpr::AO__hip_atomic_fetch_max:
125839195062SYaxun Liu case AtomicExpr::AO__opencl_atomic_fetch_max:
125939195062SYaxun Liu LibCallName = E->getValueType()->isSignedIntegerType()
126039195062SYaxun Liu ? "__atomic_fetch_max"
126139195062SYaxun Liu : "__atomic_fetch_umax";
126239195062SYaxun Liu AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1.getPointer(),
1263101309feSBevin Hansson LoweredMemTy, E->getExprLoc(), TInfo.Width);
126439195062SYaxun Liu break;
12657aefb5b6SJames Y Knight // T __atomic_nand_fetch_N(T *mem, T val, int order)
126681167fb7SJames Y Knight // T __atomic_fetch_nand_N(T *mem, T val, int order)
12677aefb5b6SJames Y Knight case AtomicExpr::AO__atomic_nand_fetch:
12687aefb5b6SJames Y Knight PostOp = llvm::Instruction::And; // the NOT is special cased below
1269f3b3ccdaSAdrian Prantl LLVM_FALLTHROUGH;
12706ea2431dSKai Luo case AtomicExpr::AO__c11_atomic_fetch_nand:
127181167fb7SJames Y Knight case AtomicExpr::AO__atomic_fetch_nand:
127281167fb7SJames Y Knight LibCallName = "__atomic_fetch_nand";
12737f416cc4SJohn McCall AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1.getPointer(),
1274101309feSBevin Hansson MemTy, E->getExprLoc(), TInfo.Width);
127581167fb7SJames Y Knight break;
1276fc207f2dSJohn McCall }
1277c7e82bd4SEd Schouten
127839195062SYaxun Liu if (E->isOpenCL()) {
127939195062SYaxun Liu LibCallName = std::string("__opencl") +
128039195062SYaxun Liu StringRef(LibCallName).drop_front(1).str();
128139195062SYaxun Liu
128239195062SYaxun Liu }
1283c7e82bd4SEd Schouten // Optimized functions have the size in their name.
1284c7e82bd4SEd Schouten if (UseOptimizedLibcall)
1285c7e82bd4SEd Schouten LibCallName += "_" + llvm::utostr(Size);
1286c7e82bd4SEd Schouten // By default, assume we return a value of the atomic type.
1287c7e82bd4SEd Schouten if (!HaveRetTy) {
1288c7e82bd4SEd Schouten if (UseOptimizedLibcall) {
1289c7e82bd4SEd Schouten // Value is returned directly.
12900392cf89SDavid Majnemer // The function returns an appropriately sized integer type.
12910392cf89SDavid Majnemer RetTy = getContext().getIntTypeForBitwidth(
1292101309feSBevin Hansson getContext().toBits(TInfo.Width), /*Signed=*/false);
1293c7e82bd4SEd Schouten } else {
1294c7e82bd4SEd Schouten // Value is returned through parameter before the order.
1295c7e82bd4SEd Schouten RetTy = getContext().VoidTy;
12967f416cc4SJohn McCall Args.add(RValue::get(EmitCastToVoidPtr(Dest.getPointer())),
12977f416cc4SJohn McCall getContext().VoidPtrTy);
1298c7e82bd4SEd Schouten }
1299c7e82bd4SEd Schouten }
1300fc207f2dSJohn McCall // order is always the last parameter
1301fc207f2dSJohn McCall Args.add(RValue::get(Order),
1302fc207f2dSJohn McCall getContext().IntTy);
130339195062SYaxun Liu if (E->isOpenCL())
130439195062SYaxun Liu Args.add(RValue::get(Scope), getContext().IntTy);
1305fc207f2dSJohn McCall
13067aefb5b6SJames Y Knight // PostOp is only needed for the atomic_*_fetch operations, and
13077aefb5b6SJames Y Knight // thus is only needed for and implemented in the
13087aefb5b6SJames Y Knight // UseOptimizedLibcall codepath.
13095cf58768STim Northover assert(UseOptimizedLibcall || (!PostOp && !PostOpMinMax));
13107aefb5b6SJames Y Knight
1311659be55dSDavid Majnemer RValue Res = emitAtomicLibcall(*this, LibCallName, RetTy, Args);
1312659be55dSDavid Majnemer // The value is returned directly from the libcall.
1313cc2a6e06STim Northover if (E->isCmpXChg())
1314fc207f2dSJohn McCall return Res;
1315cc2a6e06STim Northover
1316cc2a6e06STim Northover // The value is returned directly for optimized libcalls but the expr
1317cc2a6e06STim Northover // provided an out-param.
1318cc2a6e06STim Northover if (UseOptimizedLibcall && Res.getScalarVal()) {
1319659be55dSDavid Majnemer llvm::Value *ResVal = Res.getScalarVal();
13205cf58768STim Northover if (PostOpMinMax) {
13215cf58768STim Northover llvm::Value *LoadVal1 = Args[1].getRValue(*this).getScalarVal();
13225cf58768STim Northover ResVal = EmitPostAtomicMinMax(Builder, E->getOp(),
13235cf58768STim Northover E->getValueType()->isSignedIntegerType(),
13245cf58768STim Northover ResVal, LoadVal1);
13255cf58768STim Northover } else if (PostOp) {
13265b330e8dSYaxun Liu llvm::Value *LoadVal1 = Args[1].getRValue(*this).getScalarVal();
13277aefb5b6SJames Y Knight ResVal = Builder.CreateBinOp(PostOp, ResVal, LoadVal1);
13287aefb5b6SJames Y Knight }
13297aefb5b6SJames Y Knight if (E->getOp() == AtomicExpr::AO__atomic_nand_fetch)
13307aefb5b6SJames Y Knight ResVal = Builder.CreateNot(ResVal);
13317aefb5b6SJames Y Knight
1332cc2a6e06STim Northover Builder.CreateStore(
1333481de0edSNikita Popov ResVal, Builder.CreateElementBitCast(Dest, ResVal->getType()));
13340392cf89SDavid Majnemer }
1335cc2a6e06STim Northover
1336cc2a6e06STim Northover if (RValTy->isVoidType())
1337cc2a6e06STim Northover return RValue::get(nullptr);
1338cc2a6e06STim Northover
1339cc2a6e06STim Northover return convertTempToRValue(
1340481de0edSNikita Popov Builder.CreateElementBitCast(Dest, ConvertTypeForMem(RValTy)),
1341cc2a6e06STim Northover RValTy, E->getExprLoc());
1342fc207f2dSJohn McCall }
1343fc207f2dSJohn McCall
1344fc207f2dSJohn McCall bool IsStore = E->getOp() == AtomicExpr::AO__c11_atomic_store ||
134539195062SYaxun Liu E->getOp() == AtomicExpr::AO__opencl_atomic_store ||
1346df0560caSAnshil Gandhi E->getOp() == AtomicExpr::AO__hip_atomic_store ||
1347fc207f2dSJohn McCall E->getOp() == AtomicExpr::AO__atomic_store ||
1348fc207f2dSJohn McCall E->getOp() == AtomicExpr::AO__atomic_store_n;
1349fc207f2dSJohn McCall bool IsLoad = E->getOp() == AtomicExpr::AO__c11_atomic_load ||
135039195062SYaxun Liu E->getOp() == AtomicExpr::AO__opencl_atomic_load ||
1351df0560caSAnshil Gandhi E->getOp() == AtomicExpr::AO__hip_atomic_load ||
1352fc207f2dSJohn McCall E->getOp() == AtomicExpr::AO__atomic_load ||
1353fc207f2dSJohn McCall E->getOp() == AtomicExpr::AO__atomic_load_n;
1354fc207f2dSJohn McCall
1355fc207f2dSJohn McCall if (isa<llvm::ConstantInt>(Order)) {
1356dda2cb17SJF Bastien auto ord = cast<llvm::ConstantInt>(Order)->getZExtValue();
1357dda2cb17SJF Bastien // We should not ever get to a case where the ordering isn't a valid C ABI
1358dda2cb17SJF Bastien // value, but it's hard to enforce that in general.
1359dda2cb17SJF Bastien if (llvm::isValidAtomicOrderingCABI(ord))
1360dda2cb17SJF Bastien switch ((llvm::AtomicOrderingCABI)ord) {
1361dda2cb17SJF Bastien case llvm::AtomicOrderingCABI::relaxed:
1362dda2cb17SJF Bastien EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, IsWeak, OrderFail, Size,
136330d652a4SYaxun Liu llvm::AtomicOrdering::Monotonic, Scope);
1364fc207f2dSJohn McCall break;
1365dda2cb17SJF Bastien case llvm::AtomicOrderingCABI::consume:
1366dda2cb17SJF Bastien case llvm::AtomicOrderingCABI::acquire:
1367fc207f2dSJohn McCall if (IsStore)
1368fc207f2dSJohn McCall break; // Avoid crashing on code with undefined behavior
1369dda2cb17SJF Bastien EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, IsWeak, OrderFail, Size,
137030d652a4SYaxun Liu llvm::AtomicOrdering::Acquire, Scope);
1371fc207f2dSJohn McCall break;
1372dda2cb17SJF Bastien case llvm::AtomicOrderingCABI::release:
1373fc207f2dSJohn McCall if (IsLoad)
1374fc207f2dSJohn McCall break; // Avoid crashing on code with undefined behavior
1375dda2cb17SJF Bastien EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, IsWeak, OrderFail, Size,
137630d652a4SYaxun Liu llvm::AtomicOrdering::Release, Scope);
1377fc207f2dSJohn McCall break;
1378dda2cb17SJF Bastien case llvm::AtomicOrderingCABI::acq_rel:
1379fc207f2dSJohn McCall if (IsLoad || IsStore)
1380fc207f2dSJohn McCall break; // Avoid crashing on code with undefined behavior
1381dda2cb17SJF Bastien EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, IsWeak, OrderFail, Size,
138230d652a4SYaxun Liu llvm::AtomicOrdering::AcquireRelease, Scope);
1383fc207f2dSJohn McCall break;
1384dda2cb17SJF Bastien case llvm::AtomicOrderingCABI::seq_cst:
1385dda2cb17SJF Bastien EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, IsWeak, OrderFail, Size,
138630d652a4SYaxun Liu llvm::AtomicOrdering::SequentiallyConsistent, Scope);
1387fc207f2dSJohn McCall break;
1388fc207f2dSJohn McCall }
1389ee8d04d8SDavid Majnemer if (RValTy->isVoidType())
13908a13c418SCraig Topper return RValue::get(nullptr);
1391cc2a6e06STim Northover
1392cc2a6e06STim Northover return convertTempToRValue(
1393481de0edSNikita Popov Builder.CreateElementBitCast(Dest, ConvertTypeForMem(RValTy)),
1394cc2a6e06STim Northover RValTy, E->getExprLoc());
1395fc207f2dSJohn McCall }
1396fc207f2dSJohn McCall
1397fc207f2dSJohn McCall // Long case, when Order isn't obviously constant.
1398fc207f2dSJohn McCall
1399fc207f2dSJohn McCall // Create all the relevant BB's
14008a13c418SCraig Topper llvm::BasicBlock *MonotonicBB = nullptr, *AcquireBB = nullptr,
14018a13c418SCraig Topper *ReleaseBB = nullptr, *AcqRelBB = nullptr,
14028a13c418SCraig Topper *SeqCstBB = nullptr;
1403fc207f2dSJohn McCall MonotonicBB = createBasicBlock("monotonic", CurFn);
1404fc207f2dSJohn McCall if (!IsStore)
1405fc207f2dSJohn McCall AcquireBB = createBasicBlock("acquire", CurFn);
1406fc207f2dSJohn McCall if (!IsLoad)
1407fc207f2dSJohn McCall ReleaseBB = createBasicBlock("release", CurFn);
1408fc207f2dSJohn McCall if (!IsLoad && !IsStore)
1409fc207f2dSJohn McCall AcqRelBB = createBasicBlock("acqrel", CurFn);
1410fc207f2dSJohn McCall SeqCstBB = createBasicBlock("seqcst", CurFn);
1411fc207f2dSJohn McCall llvm::BasicBlock *ContBB = createBasicBlock("atomic.continue", CurFn);
1412fc207f2dSJohn McCall
1413fc207f2dSJohn McCall // Create the switch for the split
1414fc207f2dSJohn McCall // MonotonicBB is arbitrarily chosen as the default case; in practice, this
1415fc207f2dSJohn McCall // doesn't matter unless someone is crazy enough to use something that
1416fc207f2dSJohn McCall // doesn't fold to a constant for the ordering.
1417fc207f2dSJohn McCall Order = Builder.CreateIntCast(Order, Builder.getInt32Ty(), false);
1418fc207f2dSJohn McCall llvm::SwitchInst *SI = Builder.CreateSwitch(Order, MonotonicBB);
1419fc207f2dSJohn McCall
1420fc207f2dSJohn McCall // Emit all the different atomics
1421fc207f2dSJohn McCall Builder.SetInsertPoint(MonotonicBB);
142239195062SYaxun Liu EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, IsWeak, OrderFail, Size,
142330d652a4SYaxun Liu llvm::AtomicOrdering::Monotonic, Scope);
1424fc207f2dSJohn McCall Builder.CreateBr(ContBB);
1425fc207f2dSJohn McCall if (!IsStore) {
1426fc207f2dSJohn McCall Builder.SetInsertPoint(AcquireBB);
142739195062SYaxun Liu EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, IsWeak, OrderFail, Size,
142830d652a4SYaxun Liu llvm::AtomicOrdering::Acquire, Scope);
1429fc207f2dSJohn McCall Builder.CreateBr(ContBB);
1430dda2cb17SJF Bastien SI->addCase(Builder.getInt32((int)llvm::AtomicOrderingCABI::consume),
1431514fc61cSTim Northover AcquireBB);
1432dda2cb17SJF Bastien SI->addCase(Builder.getInt32((int)llvm::AtomicOrderingCABI::acquire),
1433514fc61cSTim Northover AcquireBB);
1434fc207f2dSJohn McCall }
1435fc207f2dSJohn McCall if (!IsLoad) {
1436fc207f2dSJohn McCall Builder.SetInsertPoint(ReleaseBB);
143739195062SYaxun Liu EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, IsWeak, OrderFail, Size,
143830d652a4SYaxun Liu llvm::AtomicOrdering::Release, Scope);
1439fc207f2dSJohn McCall Builder.CreateBr(ContBB);
1440dda2cb17SJF Bastien SI->addCase(Builder.getInt32((int)llvm::AtomicOrderingCABI::release),
1441514fc61cSTim Northover ReleaseBB);
1442fc207f2dSJohn McCall }
1443fc207f2dSJohn McCall if (!IsLoad && !IsStore) {
1444fc207f2dSJohn McCall Builder.SetInsertPoint(AcqRelBB);
144539195062SYaxun Liu EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, IsWeak, OrderFail, Size,
144630d652a4SYaxun Liu llvm::AtomicOrdering::AcquireRelease, Scope);
1447fc207f2dSJohn McCall Builder.CreateBr(ContBB);
1448dda2cb17SJF Bastien SI->addCase(Builder.getInt32((int)llvm::AtomicOrderingCABI::acq_rel),
1449514fc61cSTim Northover AcqRelBB);
1450fc207f2dSJohn McCall }
1451fc207f2dSJohn McCall Builder.SetInsertPoint(SeqCstBB);
145239195062SYaxun Liu EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, IsWeak, OrderFail, Size,
145330d652a4SYaxun Liu llvm::AtomicOrdering::SequentiallyConsistent, Scope);
1454fc207f2dSJohn McCall Builder.CreateBr(ContBB);
1455dda2cb17SJF Bastien SI->addCase(Builder.getInt32((int)llvm::AtomicOrderingCABI::seq_cst),
1456514fc61cSTim Northover SeqCstBB);
1457fc207f2dSJohn McCall
1458fc207f2dSJohn McCall // Cleanup and return
1459fc207f2dSJohn McCall Builder.SetInsertPoint(ContBB);
1460ee8d04d8SDavid Majnemer if (RValTy->isVoidType())
14618a13c418SCraig Topper return RValue::get(nullptr);
1462cc2a6e06STim Northover
1463cc2a6e06STim Northover assert(Atomics.getValueSizeInBits() <= Atomics.getAtomicSizeInBits());
1464cc2a6e06STim Northover return convertTempToRValue(
1465481de0edSNikita Popov Builder.CreateElementBitCast(Dest, ConvertTypeForMem(RValTy)),
1466cc2a6e06STim Northover RValTy, E->getExprLoc());
1467fc207f2dSJohn McCall }
1468a8ec7eb9SJohn McCall
emitCastToAtomicIntPointer(Address addr) const14697f416cc4SJohn McCall Address AtomicInfo::emitCastToAtomicIntPointer(Address addr) const {
1470a8ec7eb9SJohn McCall llvm::IntegerType *ty =
1471a8ec7eb9SJohn McCall llvm::IntegerType::get(CGF.getLLVMContext(), AtomicSizeInBits);
1472481de0edSNikita Popov return CGF.Builder.CreateElementBitCast(addr, ty);
1473a8ec7eb9SJohn McCall }
1474a8ec7eb9SJohn McCall
convertToAtomicIntPointer(Address Addr) const1475cc2a6e06STim Northover Address AtomicInfo::convertToAtomicIntPointer(Address Addr) const {
1476cc2a6e06STim Northover llvm::Type *Ty = Addr.getElementType();
1477cc2a6e06STim Northover uint64_t SourceSizeInBits = CGF.CGM.getDataLayout().getTypeSizeInBits(Ty);
1478cc2a6e06STim Northover if (SourceSizeInBits != AtomicSizeInBits) {
1479cc2a6e06STim Northover Address Tmp = CreateTempAlloca();
1480cc2a6e06STim Northover CGF.Builder.CreateMemCpy(Tmp, Addr,
1481cc2a6e06STim Northover std::min(AtomicSizeInBits, SourceSizeInBits) / 8);
1482cc2a6e06STim Northover Addr = Tmp;
1483cc2a6e06STim Northover }
1484cc2a6e06STim Northover
1485cc2a6e06STim Northover return emitCastToAtomicIntPointer(Addr);
1486cc2a6e06STim Northover }
1487cc2a6e06STim Northover
convertAtomicTempToRValue(Address addr,AggValueSlot resultSlot,SourceLocation loc,bool asValue) const14887f416cc4SJohn McCall RValue AtomicInfo::convertAtomicTempToRValue(Address addr,
14892d84e842SNick Lewycky AggValueSlot resultSlot,
14907f416cc4SJohn McCall SourceLocation loc,
14917f416cc4SJohn McCall bool asValue) const {
1492b57056f4SAlexey Bataev if (LVal.isSimple()) {
1493be4504dfSEli Friedman if (EvaluationKind == TEK_Aggregate)
1494a8ec7eb9SJohn McCall return resultSlot.asRValue();
1495a8ec7eb9SJohn McCall
1496a8ec7eb9SJohn McCall // Drill into the padding structure if we have one.
1497a8ec7eb9SJohn McCall if (hasPadding())
1498751fe286SJames Y Knight addr = CGF.Builder.CreateStructGEP(addr, 0);
1499a8ec7eb9SJohn McCall
1500a8ec7eb9SJohn McCall // Otherwise, just convert the temporary to an r-value using the
1501a8ec7eb9SJohn McCall // normal conversion routine.
15022d84e842SNick Lewycky return CGF.convertTempToRValue(addr, getValueType(), loc);
15031ed728c4SDavid Blaikie }
15047f416cc4SJohn McCall if (!asValue)
1505b8329261SAlexey Bataev // Get RValue from temp memory as atomic for non-simple lvalues
15067f416cc4SJohn McCall return RValue::get(CGF.Builder.CreateLoad(addr));
15071ed728c4SDavid Blaikie if (LVal.isBitField())
15087f416cc4SJohn McCall return CGF.EmitLoadOfBitfieldLValue(
15097f416cc4SJohn McCall LValue::MakeBitfield(addr, LVal.getBitFieldInfo(), LVal.getType(),
1510d17f12a3SIvan A. Kosarev LVal.getBaseInfo(), TBAAAccessInfo()), loc);
15111ed728c4SDavid Blaikie if (LVal.isVectorElt())
15127f416cc4SJohn McCall return CGF.EmitLoadOfLValue(
15137f416cc4SJohn McCall LValue::MakeVectorElt(addr, LVal.getVectorIdx(), LVal.getType(),
1514d17f12a3SIvan A. Kosarev LVal.getBaseInfo(), TBAAAccessInfo()), loc);
1515b57056f4SAlexey Bataev assert(LVal.isExtVectorElt());
1516b57056f4SAlexey Bataev return CGF.EmitLoadOfExtVectorElementLValue(LValue::MakeExtVectorElt(
15177f416cc4SJohn McCall addr, LVal.getExtVectorElts(), LVal.getType(),
1518d17f12a3SIvan A. Kosarev LVal.getBaseInfo(), TBAAAccessInfo()));
1519a8ec7eb9SJohn McCall }
1520a8ec7eb9SJohn McCall
ConvertIntToValueOrAtomic(llvm::Value * IntVal,AggValueSlot ResultSlot,SourceLocation Loc,bool AsValue) const1521b8329261SAlexey Bataev RValue AtomicInfo::ConvertIntToValueOrAtomic(llvm::Value *IntVal,
1522452d8e11SAlexey Bataev AggValueSlot ResultSlot,
1523b8329261SAlexey Bataev SourceLocation Loc,
1524b8329261SAlexey Bataev bool AsValue) const {
1525452d8e11SAlexey Bataev // Try not to in some easy cases.
1526452d8e11SAlexey Bataev assert(IntVal->getType()->isIntegerTy() && "Expected integer value");
1527b8329261SAlexey Bataev if (getEvaluationKind() == TEK_Scalar &&
1528b8329261SAlexey Bataev (((!LVal.isBitField() ||
1529b8329261SAlexey Bataev LVal.getBitFieldInfo().Size == ValueSizeInBits) &&
1530b8329261SAlexey Bataev !hasPadding()) ||
1531b8329261SAlexey Bataev !AsValue)) {
1532b8329261SAlexey Bataev auto *ValTy = AsValue
1533b8329261SAlexey Bataev ? CGF.ConvertTypeForMem(ValueTy)
153499adacbcSNikita Popov : getAtomicAddress().getElementType();
1535452d8e11SAlexey Bataev if (ValTy->isIntegerTy()) {
1536452d8e11SAlexey Bataev assert(IntVal->getType() == ValTy && "Different integer types.");
1537eeaec265SDavid Majnemer return RValue::get(CGF.EmitFromMemory(IntVal, ValueTy));
1538452d8e11SAlexey Bataev } else if (ValTy->isPointerTy())
1539452d8e11SAlexey Bataev return RValue::get(CGF.Builder.CreateIntToPtr(IntVal, ValTy));
1540452d8e11SAlexey Bataev else if (llvm::CastInst::isBitCastable(IntVal->getType(), ValTy))
1541452d8e11SAlexey Bataev return RValue::get(CGF.Builder.CreateBitCast(IntVal, ValTy));
1542452d8e11SAlexey Bataev }
1543452d8e11SAlexey Bataev
1544452d8e11SAlexey Bataev // Create a temporary. This needs to be big enough to hold the
1545452d8e11SAlexey Bataev // atomic integer.
15467f416cc4SJohn McCall Address Temp = Address::invalid();
1547452d8e11SAlexey Bataev bool TempIsVolatile = false;
1548b8329261SAlexey Bataev if (AsValue && getEvaluationKind() == TEK_Aggregate) {
1549452d8e11SAlexey Bataev assert(!ResultSlot.isIgnored());
15507f416cc4SJohn McCall Temp = ResultSlot.getAddress();
1551452d8e11SAlexey Bataev TempIsVolatile = ResultSlot.isVolatile();
1552452d8e11SAlexey Bataev } else {
1553b8329261SAlexey Bataev Temp = CreateTempAlloca();
1554452d8e11SAlexey Bataev }
1555452d8e11SAlexey Bataev
1556452d8e11SAlexey Bataev // Slam the integer into the temporary.
15577f416cc4SJohn McCall Address CastTemp = emitCastToAtomicIntPointer(Temp);
15587f416cc4SJohn McCall CGF.Builder.CreateStore(IntVal, CastTemp)
1559452d8e11SAlexey Bataev ->setVolatile(TempIsVolatile);
1560452d8e11SAlexey Bataev
15617f416cc4SJohn McCall return convertAtomicTempToRValue(Temp, ResultSlot, Loc, AsValue);
1562b8329261SAlexey Bataev }
1563b8329261SAlexey Bataev
EmitAtomicLoadLibcall(llvm::Value * AddForLoaded,llvm::AtomicOrdering AO,bool)1564b8329261SAlexey Bataev void AtomicInfo::EmitAtomicLoadLibcall(llvm::Value *AddForLoaded,
1565b8329261SAlexey Bataev llvm::AtomicOrdering AO, bool) {
1566b8329261SAlexey Bataev // void __atomic_load(size_t size, void *mem, void *return, int order);
1567b8329261SAlexey Bataev CallArgList Args;
1568b8329261SAlexey Bataev Args.add(RValue::get(getAtomicSizeValue()), CGF.getContext().getSizeType());
15697f416cc4SJohn McCall Args.add(RValue::get(CGF.EmitCastToVoidPtr(getAtomicPointer())),
1570b8329261SAlexey Bataev CGF.getContext().VoidPtrTy);
1571b8329261SAlexey Bataev Args.add(RValue::get(CGF.EmitCastToVoidPtr(AddForLoaded)),
1572b8329261SAlexey Bataev CGF.getContext().VoidPtrTy);
1573dda2cb17SJF Bastien Args.add(
1574dda2cb17SJF Bastien RValue::get(llvm::ConstantInt::get(CGF.IntTy, (int)llvm::toCABI(AO))),
1575b8329261SAlexey Bataev CGF.getContext().IntTy);
1576b8329261SAlexey Bataev emitAtomicLibcall(CGF, "__atomic_load", CGF.getContext().VoidTy, Args);
1577b8329261SAlexey Bataev }
1578b8329261SAlexey Bataev
EmitAtomicLoadOp(llvm::AtomicOrdering AO,bool IsVolatile)1579b8329261SAlexey Bataev llvm::Value *AtomicInfo::EmitAtomicLoadOp(llvm::AtomicOrdering AO,
1580b8329261SAlexey Bataev bool IsVolatile) {
1581b8329261SAlexey Bataev // Okay, we're doing this natively.
15827f416cc4SJohn McCall Address Addr = getAtomicAddressAsAtomicIntPointer();
1583b8329261SAlexey Bataev llvm::LoadInst *Load = CGF.Builder.CreateLoad(Addr, "atomic-load");
1584b8329261SAlexey Bataev Load->setAtomic(AO);
1585b8329261SAlexey Bataev
1586b8329261SAlexey Bataev // Other decoration.
1587b8329261SAlexey Bataev if (IsVolatile)
1588b8329261SAlexey Bataev Load->setVolatile(true);
1589383890baSIvan A. Kosarev CGF.CGM.DecorateInstructionWithTBAA(Load, LVal.getTBAAInfo());
1590b8329261SAlexey Bataev return Load;
1591452d8e11SAlexey Bataev }
1592452d8e11SAlexey Bataev
1593a5b195a1SDavid Majnemer /// An LValue is a candidate for having its loads and stores be made atomic if
1594a5b195a1SDavid Majnemer /// we are operating under /volatile:ms *and* the LValue itself is volatile and
1595a5b195a1SDavid Majnemer /// performing such an operation can be performed without a libcall.
LValueIsSuitableForInlineAtomic(LValue LV)1596a5b195a1SDavid Majnemer bool CodeGenFunction::LValueIsSuitableForInlineAtomic(LValue LV) {
15977f416cc4SJohn McCall if (!CGM.getCodeGenOpts().MSVolatile) return false;
1598a5b195a1SDavid Majnemer AtomicInfo AI(*this, LV);
1599a5b195a1SDavid Majnemer bool IsVolatile = LV.isVolatile() || hasVolatileMember(LV.getType());
1600a5b195a1SDavid Majnemer // An atomic is inline if we don't need to use a libcall.
1601a5b195a1SDavid Majnemer bool AtomicIsInline = !AI.shouldUseLibcall();
1602fc80b6e5SDavid Majnemer // MSVC doesn't seem to do this for types wider than a pointer.
1603a38c9f1fSDavid Majnemer if (getContext().getTypeSize(LV.getType()) >
1604fc80b6e5SDavid Majnemer getContext().getTypeSize(getContext().getIntPtrType()))
1605fc80b6e5SDavid Majnemer return false;
1606a38c9f1fSDavid Majnemer return IsVolatile && AtomicIsInline;
1607a5b195a1SDavid Majnemer }
1608a5b195a1SDavid Majnemer
EmitAtomicLoad(LValue LV,SourceLocation SL,AggValueSlot Slot)1609a5b195a1SDavid Majnemer RValue CodeGenFunction::EmitAtomicLoad(LValue LV, SourceLocation SL,
1610a5b195a1SDavid Majnemer AggValueSlot Slot) {
1611a5b195a1SDavid Majnemer llvm::AtomicOrdering AO;
1612a5b195a1SDavid Majnemer bool IsVolatile = LV.isVolatileQualified();
1613a5b195a1SDavid Majnemer if (LV.getType()->isAtomicType()) {
161492f4ef10SJF Bastien AO = llvm::AtomicOrdering::SequentiallyConsistent;
1615a5b195a1SDavid Majnemer } else {
161692f4ef10SJF Bastien AO = llvm::AtomicOrdering::Acquire;
1617a5b195a1SDavid Majnemer IsVolatile = true;
1618a5b195a1SDavid Majnemer }
1619a5b195a1SDavid Majnemer return EmitAtomicLoad(LV, SL, AO, IsVolatile, Slot);
1620a5b195a1SDavid Majnemer }
1621a5b195a1SDavid Majnemer
EmitAtomicLoad(AggValueSlot ResultSlot,SourceLocation Loc,bool AsValue,llvm::AtomicOrdering AO,bool IsVolatile)1622b8329261SAlexey Bataev RValue AtomicInfo::EmitAtomicLoad(AggValueSlot ResultSlot, SourceLocation Loc,
1623b8329261SAlexey Bataev bool AsValue, llvm::AtomicOrdering AO,
1624b8329261SAlexey Bataev bool IsVolatile) {
1625b8329261SAlexey Bataev // Check whether we should use a library call.
1626b8329261SAlexey Bataev if (shouldUseLibcall()) {
16277f416cc4SJohn McCall Address TempAddr = Address::invalid();
1628b8329261SAlexey Bataev if (LVal.isSimple() && !ResultSlot.isIgnored()) {
1629b8329261SAlexey Bataev assert(getEvaluationKind() == TEK_Aggregate);
16307f416cc4SJohn McCall TempAddr = ResultSlot.getAddress();
1631b8329261SAlexey Bataev } else
1632b8329261SAlexey Bataev TempAddr = CreateTempAlloca();
1633b8329261SAlexey Bataev
16347f416cc4SJohn McCall EmitAtomicLoadLibcall(TempAddr.getPointer(), AO, IsVolatile);
1635b8329261SAlexey Bataev
1636b8329261SAlexey Bataev // Okay, turn that back into the original value or whole atomic (for
1637b8329261SAlexey Bataev // non-simple lvalues) type.
16387f416cc4SJohn McCall return convertAtomicTempToRValue(TempAddr, ResultSlot, Loc, AsValue);
1639b8329261SAlexey Bataev }
1640b8329261SAlexey Bataev
1641b8329261SAlexey Bataev // Okay, we're doing this natively.
1642b8329261SAlexey Bataev auto *Load = EmitAtomicLoadOp(AO, IsVolatile);
1643b8329261SAlexey Bataev
1644b8329261SAlexey Bataev // If we're ignoring an aggregate return, don't do anything.
1645b8329261SAlexey Bataev if (getEvaluationKind() == TEK_Aggregate && ResultSlot.isIgnored())
16467f416cc4SJohn McCall return RValue::getAggregate(Address::invalid(), false);
1647b8329261SAlexey Bataev
1648b8329261SAlexey Bataev // Okay, turn that back into the original value or atomic (for non-simple
1649b8329261SAlexey Bataev // lvalues) type.
1650b8329261SAlexey Bataev return ConvertIntToValueOrAtomic(Load, ResultSlot, Loc, AsValue);
1651b8329261SAlexey Bataev }
1652b8329261SAlexey Bataev
1653a8ec7eb9SJohn McCall /// Emit a load from an l-value of atomic type. Note that the r-value
1654a8ec7eb9SJohn McCall /// we produce is an r-value of the atomic *value* type.
EmitAtomicLoad(LValue src,SourceLocation loc,llvm::AtomicOrdering AO,bool IsVolatile,AggValueSlot resultSlot)16552d84e842SNick Lewycky RValue CodeGenFunction::EmitAtomicLoad(LValue src, SourceLocation loc,
1656a5b195a1SDavid Majnemer llvm::AtomicOrdering AO, bool IsVolatile,
16572d84e842SNick Lewycky AggValueSlot resultSlot) {
1658b8329261SAlexey Bataev AtomicInfo Atomics(*this, src);
1659b8329261SAlexey Bataev return Atomics.EmitAtomicLoad(resultSlot, loc, /*AsValue=*/true, AO,
1660b8329261SAlexey Bataev IsVolatile);
1661b57056f4SAlexey Bataev }
1662a8ec7eb9SJohn McCall
1663a8ec7eb9SJohn McCall /// Copy an r-value into memory as part of storing to an atomic type.
1664a8ec7eb9SJohn McCall /// This needs to create a bit-pattern suitable for atomic operations.
emitCopyIntoMemory(RValue rvalue) const1665b57056f4SAlexey Bataev void AtomicInfo::emitCopyIntoMemory(RValue rvalue) const {
1666b57056f4SAlexey Bataev assert(LVal.isSimple());
1667a8ec7eb9SJohn McCall // If we have an r-value, the rvalue should be of the atomic type,
1668a8ec7eb9SJohn McCall // which means that the caller is responsible for having zeroed
1669a8ec7eb9SJohn McCall // any padding. Just do an aggregate copy of that type.
1670a8ec7eb9SJohn McCall if (rvalue.isAggregate()) {
16711860b520SIvan A. Kosarev LValue Dest = CGF.MakeAddrLValue(getAtomicAddress(), getAtomicType());
16721860b520SIvan A. Kosarev LValue Src = CGF.MakeAddrLValue(rvalue.getAggregateAddress(),
16731860b520SIvan A. Kosarev getAtomicType());
16741860b520SIvan A. Kosarev bool IsVolatile = rvalue.isVolatileQualified() ||
16751860b520SIvan A. Kosarev LVal.isVolatileQualified();
1676e78fac51SRichard Smith CGF.EmitAggregateCopy(Dest, Src, getAtomicType(),
1677e78fac51SRichard Smith AggValueSlot::DoesNotOverlap, IsVolatile);
1678a8ec7eb9SJohn McCall return;
1679a8ec7eb9SJohn McCall }
1680a8ec7eb9SJohn McCall
1681a8ec7eb9SJohn McCall // Okay, otherwise we're copying stuff.
1682a8ec7eb9SJohn McCall
1683a8ec7eb9SJohn McCall // Zero out the buffer if necessary.
1684b57056f4SAlexey Bataev emitMemSetZeroIfNecessary();
1685a8ec7eb9SJohn McCall
1686a8ec7eb9SJohn McCall // Drill past the padding if present.
1687b57056f4SAlexey Bataev LValue TempLVal = projectValue();
1688a8ec7eb9SJohn McCall
1689a8ec7eb9SJohn McCall // Okay, store the rvalue in.
1690a8ec7eb9SJohn McCall if (rvalue.isScalar()) {
1691b57056f4SAlexey Bataev CGF.EmitStoreOfScalar(rvalue.getScalarVal(), TempLVal, /*init*/ true);
1692a8ec7eb9SJohn McCall } else {
1693b57056f4SAlexey Bataev CGF.EmitStoreOfComplex(rvalue.getComplexVal(), TempLVal, /*init*/ true);
1694a8ec7eb9SJohn McCall }
1695a8ec7eb9SJohn McCall }
1696a8ec7eb9SJohn McCall
1697a8ec7eb9SJohn McCall
1698a8ec7eb9SJohn McCall /// Materialize an r-value into memory for the purposes of storing it
1699a8ec7eb9SJohn McCall /// to an atomic type.
materializeRValue(RValue rvalue) const17007f416cc4SJohn McCall Address AtomicInfo::materializeRValue(RValue rvalue) const {
1701a8ec7eb9SJohn McCall // Aggregate r-values are already in memory, and EmitAtomicStore
1702a8ec7eb9SJohn McCall // requires them to be values of the atomic type.
1703a8ec7eb9SJohn McCall if (rvalue.isAggregate())
17047f416cc4SJohn McCall return rvalue.getAggregateAddress();
1705a8ec7eb9SJohn McCall
1706a8ec7eb9SJohn McCall // Otherwise, make a temporary and materialize into it.
17077f416cc4SJohn McCall LValue TempLV = CGF.MakeAddrLValue(CreateTempAlloca(), getAtomicType());
1708b8329261SAlexey Bataev AtomicInfo Atomics(CGF, TempLV);
1709b57056f4SAlexey Bataev Atomics.emitCopyIntoMemory(rvalue);
1710f139ae3dSAkira Hatanaka return TempLV.getAddress(CGF);
1711a8ec7eb9SJohn McCall }
1712a8ec7eb9SJohn McCall
convertRValueToInt(RValue RVal) const1713452d8e11SAlexey Bataev llvm::Value *AtomicInfo::convertRValueToInt(RValue RVal) const {
1714452d8e11SAlexey Bataev // If we've got a scalar value of the right size, try to avoid going
1715452d8e11SAlexey Bataev // through memory.
1716b8329261SAlexey Bataev if (RVal.isScalar() && (!hasPadding() || !LVal.isSimple())) {
1717452d8e11SAlexey Bataev llvm::Value *Value = RVal.getScalarVal();
1718452d8e11SAlexey Bataev if (isa<llvm::IntegerType>(Value->getType()))
1719b4505a72SAlexey Bataev return CGF.EmitToMemory(Value, ValueTy);
1720452d8e11SAlexey Bataev else {
1721b8329261SAlexey Bataev llvm::IntegerType *InputIntTy = llvm::IntegerType::get(
1722b8329261SAlexey Bataev CGF.getLLVMContext(),
1723b8329261SAlexey Bataev LVal.isSimple() ? getValueSizeInBits() : getAtomicSizeInBits());
1724452d8e11SAlexey Bataev if (isa<llvm::PointerType>(Value->getType()))
1725452d8e11SAlexey Bataev return CGF.Builder.CreatePtrToInt(Value, InputIntTy);
1726452d8e11SAlexey Bataev else if (llvm::BitCastInst::isBitCastable(Value->getType(), InputIntTy))
1727452d8e11SAlexey Bataev return CGF.Builder.CreateBitCast(Value, InputIntTy);
1728452d8e11SAlexey Bataev }
1729452d8e11SAlexey Bataev }
1730452d8e11SAlexey Bataev // Otherwise, we need to go through memory.
1731452d8e11SAlexey Bataev // Put the r-value in memory.
17327f416cc4SJohn McCall Address Addr = materializeRValue(RVal);
1733452d8e11SAlexey Bataev
1734452d8e11SAlexey Bataev // Cast the temporary to the atomic int type and pull a value out.
1735452d8e11SAlexey Bataev Addr = emitCastToAtomicIntPointer(Addr);
17367f416cc4SJohn McCall return CGF.Builder.CreateLoad(Addr);
1737452d8e11SAlexey Bataev }
1738452d8e11SAlexey Bataev
EmitAtomicCompareExchangeOp(llvm::Value * ExpectedVal,llvm::Value * DesiredVal,llvm::AtomicOrdering Success,llvm::AtomicOrdering Failure,bool IsWeak)1739f0ab553fSAlexey Bataev std::pair<llvm::Value *, llvm::Value *> AtomicInfo::EmitAtomicCompareExchangeOp(
1740f0ab553fSAlexey Bataev llvm::Value *ExpectedVal, llvm::Value *DesiredVal,
1741f0ab553fSAlexey Bataev llvm::AtomicOrdering Success, llvm::AtomicOrdering Failure, bool IsWeak) {
1742b8329261SAlexey Bataev // Do the atomic store.
17437f416cc4SJohn McCall Address Addr = getAtomicAddressAsAtomicIntPointer();
17447f416cc4SJohn McCall auto *Inst = CGF.Builder.CreateAtomicCmpXchg(Addr.getPointer(),
17457f416cc4SJohn McCall ExpectedVal, DesiredVal,
1746b4505a72SAlexey Bataev Success, Failure);
1747b8329261SAlexey Bataev // Other decoration.
1748b8329261SAlexey Bataev Inst->setVolatile(LVal.isVolatileQualified());
1749b8329261SAlexey Bataev Inst->setWeak(IsWeak);
1750b8329261SAlexey Bataev
1751b8329261SAlexey Bataev // Okay, turn that back into the original value type.
1752b8329261SAlexey Bataev auto *PreviousVal = CGF.Builder.CreateExtractValue(Inst, /*Idxs=*/0);
1753b8329261SAlexey Bataev auto *SuccessFailureVal = CGF.Builder.CreateExtractValue(Inst, /*Idxs=*/1);
1754f0ab553fSAlexey Bataev return std::make_pair(PreviousVal, SuccessFailureVal);
1755b8329261SAlexey Bataev }
1756b8329261SAlexey Bataev
1757f0ab553fSAlexey Bataev llvm::Value *
EmitAtomicCompareExchangeLibcall(llvm::Value * ExpectedAddr,llvm::Value * DesiredAddr,llvm::AtomicOrdering Success,llvm::AtomicOrdering Failure)1758f0ab553fSAlexey Bataev AtomicInfo::EmitAtomicCompareExchangeLibcall(llvm::Value *ExpectedAddr,
1759f0ab553fSAlexey Bataev llvm::Value *DesiredAddr,
1760b8329261SAlexey Bataev llvm::AtomicOrdering Success,
1761b8329261SAlexey Bataev llvm::AtomicOrdering Failure) {
1762b8329261SAlexey Bataev // bool __atomic_compare_exchange(size_t size, void *obj, void *expected,
1763b8329261SAlexey Bataev // void *desired, int success, int failure);
1764b8329261SAlexey Bataev CallArgList Args;
1765b8329261SAlexey Bataev Args.add(RValue::get(getAtomicSizeValue()), CGF.getContext().getSizeType());
17667f416cc4SJohn McCall Args.add(RValue::get(CGF.EmitCastToVoidPtr(getAtomicPointer())),
1767b8329261SAlexey Bataev CGF.getContext().VoidPtrTy);
1768b8329261SAlexey Bataev Args.add(RValue::get(CGF.EmitCastToVoidPtr(ExpectedAddr)),
1769b8329261SAlexey Bataev CGF.getContext().VoidPtrTy);
1770b8329261SAlexey Bataev Args.add(RValue::get(CGF.EmitCastToVoidPtr(DesiredAddr)),
1771b8329261SAlexey Bataev CGF.getContext().VoidPtrTy);
1772dda2cb17SJF Bastien Args.add(RValue::get(
1773dda2cb17SJF Bastien llvm::ConstantInt::get(CGF.IntTy, (int)llvm::toCABI(Success))),
1774b8329261SAlexey Bataev CGF.getContext().IntTy);
1775dda2cb17SJF Bastien Args.add(RValue::get(
1776dda2cb17SJF Bastien llvm::ConstantInt::get(CGF.IntTy, (int)llvm::toCABI(Failure))),
1777b8329261SAlexey Bataev CGF.getContext().IntTy);
1778b8329261SAlexey Bataev auto SuccessFailureRVal = emitAtomicLibcall(CGF, "__atomic_compare_exchange",
1779b8329261SAlexey Bataev CGF.getContext().BoolTy, Args);
1780b4505a72SAlexey Bataev
1781f0ab553fSAlexey Bataev return SuccessFailureRVal.getScalarVal();
1782b8329261SAlexey Bataev }
1783b8329261SAlexey Bataev
EmitAtomicCompareExchange(RValue Expected,RValue Desired,llvm::AtomicOrdering Success,llvm::AtomicOrdering Failure,bool IsWeak)1784b4505a72SAlexey Bataev std::pair<RValue, llvm::Value *> AtomicInfo::EmitAtomicCompareExchange(
1785b8329261SAlexey Bataev RValue Expected, RValue Desired, llvm::AtomicOrdering Success,
1786b8329261SAlexey Bataev llvm::AtomicOrdering Failure, bool IsWeak) {
1787b8329261SAlexey Bataev // Check whether we should use a library call.
1788b8329261SAlexey Bataev if (shouldUseLibcall()) {
1789b8329261SAlexey Bataev // Produce a source address.
17907f416cc4SJohn McCall Address ExpectedAddr = materializeRValue(Expected);
17917f416cc4SJohn McCall Address DesiredAddr = materializeRValue(Desired);
17927f416cc4SJohn McCall auto *Res = EmitAtomicCompareExchangeLibcall(ExpectedAddr.getPointer(),
17937f416cc4SJohn McCall DesiredAddr.getPointer(),
1794f0ab553fSAlexey Bataev Success, Failure);
1795f0ab553fSAlexey Bataev return std::make_pair(
17967f416cc4SJohn McCall convertAtomicTempToRValue(ExpectedAddr, AggValueSlot::ignored(),
1797f0ab553fSAlexey Bataev SourceLocation(), /*AsValue=*/false),
1798f0ab553fSAlexey Bataev Res);
1799b8329261SAlexey Bataev }
1800b8329261SAlexey Bataev
1801b8329261SAlexey Bataev // If we've got a scalar value of the right size, try to avoid going
1802b8329261SAlexey Bataev // through memory.
1803f0ab553fSAlexey Bataev auto *ExpectedVal = convertRValueToInt(Expected);
1804f0ab553fSAlexey Bataev auto *DesiredVal = convertRValueToInt(Desired);
1805f0ab553fSAlexey Bataev auto Res = EmitAtomicCompareExchangeOp(ExpectedVal, DesiredVal, Success,
1806f0ab553fSAlexey Bataev Failure, IsWeak);
1807f0ab553fSAlexey Bataev return std::make_pair(
1808f0ab553fSAlexey Bataev ConvertIntToValueOrAtomic(Res.first, AggValueSlot::ignored(),
1809f0ab553fSAlexey Bataev SourceLocation(), /*AsValue=*/false),
1810f0ab553fSAlexey Bataev Res.second);
1811f0ab553fSAlexey Bataev }
1812f0ab553fSAlexey Bataev
1813f0ab553fSAlexey Bataev static void
EmitAtomicUpdateValue(CodeGenFunction & CGF,AtomicInfo & Atomics,RValue OldRVal,const llvm::function_ref<RValue (RValue)> & UpdateOp,Address DesiredAddr)1814f0ab553fSAlexey Bataev EmitAtomicUpdateValue(CodeGenFunction &CGF, AtomicInfo &Atomics, RValue OldRVal,
1815f0ab553fSAlexey Bataev const llvm::function_ref<RValue(RValue)> &UpdateOp,
18167f416cc4SJohn McCall Address DesiredAddr) {
1817f0ab553fSAlexey Bataev RValue UpRVal;
1818f0ab553fSAlexey Bataev LValue AtomicLVal = Atomics.getAtomicLValue();
1819f0ab553fSAlexey Bataev LValue DesiredLVal;
1820f0ab553fSAlexey Bataev if (AtomicLVal.isSimple()) {
1821f0ab553fSAlexey Bataev UpRVal = OldRVal;
18227f416cc4SJohn McCall DesiredLVal = CGF.MakeAddrLValue(DesiredAddr, AtomicLVal.getType());
1823f0ab553fSAlexey Bataev } else {
1824144a43a2SAmy Huang // Build new lvalue for temp address.
18257f416cc4SJohn McCall Address Ptr = Atomics.materializeRValue(OldRVal);
18267f416cc4SJohn McCall LValue UpdateLVal;
1827f0ab553fSAlexey Bataev if (AtomicLVal.isBitField()) {
1828f0ab553fSAlexey Bataev UpdateLVal =
1829f0ab553fSAlexey Bataev LValue::MakeBitfield(Ptr, AtomicLVal.getBitFieldInfo(),
18307f416cc4SJohn McCall AtomicLVal.getType(),
1831d17f12a3SIvan A. Kosarev AtomicLVal.getBaseInfo(),
1832d17f12a3SIvan A. Kosarev AtomicLVal.getTBAAInfo());
1833f0ab553fSAlexey Bataev DesiredLVal =
1834f0ab553fSAlexey Bataev LValue::MakeBitfield(DesiredAddr, AtomicLVal.getBitFieldInfo(),
1835d17f12a3SIvan A. Kosarev AtomicLVal.getType(), AtomicLVal.getBaseInfo(),
1836d17f12a3SIvan A. Kosarev AtomicLVal.getTBAAInfo());
1837f0ab553fSAlexey Bataev } else if (AtomicLVal.isVectorElt()) {
1838f0ab553fSAlexey Bataev UpdateLVal = LValue::MakeVectorElt(Ptr, AtomicLVal.getVectorIdx(),
1839f0ab553fSAlexey Bataev AtomicLVal.getType(),
1840d17f12a3SIvan A. Kosarev AtomicLVal.getBaseInfo(),
1841d17f12a3SIvan A. Kosarev AtomicLVal.getTBAAInfo());
1842f0ab553fSAlexey Bataev DesiredLVal = LValue::MakeVectorElt(
1843f0ab553fSAlexey Bataev DesiredAddr, AtomicLVal.getVectorIdx(), AtomicLVal.getType(),
1844d17f12a3SIvan A. Kosarev AtomicLVal.getBaseInfo(), AtomicLVal.getTBAAInfo());
1845f0ab553fSAlexey Bataev } else {
1846f0ab553fSAlexey Bataev assert(AtomicLVal.isExtVectorElt());
1847f0ab553fSAlexey Bataev UpdateLVal = LValue::MakeExtVectorElt(Ptr, AtomicLVal.getExtVectorElts(),
1848f0ab553fSAlexey Bataev AtomicLVal.getType(),
1849d17f12a3SIvan A. Kosarev AtomicLVal.getBaseInfo(),
1850d17f12a3SIvan A. Kosarev AtomicLVal.getTBAAInfo());
1851f0ab553fSAlexey Bataev DesiredLVal = LValue::MakeExtVectorElt(
1852f0ab553fSAlexey Bataev DesiredAddr, AtomicLVal.getExtVectorElts(), AtomicLVal.getType(),
1853d17f12a3SIvan A. Kosarev AtomicLVal.getBaseInfo(), AtomicLVal.getTBAAInfo());
1854f0ab553fSAlexey Bataev }
1855f0ab553fSAlexey Bataev UpRVal = CGF.EmitLoadOfLValue(UpdateLVal, SourceLocation());
1856f0ab553fSAlexey Bataev }
1857144a43a2SAmy Huang // Store new value in the corresponding memory area.
1858f0ab553fSAlexey Bataev RValue NewRVal = UpdateOp(UpRVal);
1859f0ab553fSAlexey Bataev if (NewRVal.isScalar()) {
1860f0ab553fSAlexey Bataev CGF.EmitStoreThroughLValue(NewRVal, DesiredLVal);
1861f0ab553fSAlexey Bataev } else {
1862f0ab553fSAlexey Bataev assert(NewRVal.isComplex());
1863f0ab553fSAlexey Bataev CGF.EmitStoreOfComplex(NewRVal.getComplexVal(), DesiredLVal,
1864f0ab553fSAlexey Bataev /*isInit=*/false);
1865f0ab553fSAlexey Bataev }
1866f0ab553fSAlexey Bataev }
1867f0ab553fSAlexey Bataev
EmitAtomicUpdateLibcall(llvm::AtomicOrdering AO,const llvm::function_ref<RValue (RValue)> & UpdateOp,bool IsVolatile)1868f0ab553fSAlexey Bataev void AtomicInfo::EmitAtomicUpdateLibcall(
1869f0ab553fSAlexey Bataev llvm::AtomicOrdering AO, const llvm::function_ref<RValue(RValue)> &UpdateOp,
1870f0ab553fSAlexey Bataev bool IsVolatile) {
1871f0ab553fSAlexey Bataev auto Failure = llvm::AtomicCmpXchgInst::getStrongestFailureOrdering(AO);
1872f0ab553fSAlexey Bataev
18737f416cc4SJohn McCall Address ExpectedAddr = CreateTempAlloca();
1874f0ab553fSAlexey Bataev
18757f416cc4SJohn McCall EmitAtomicLoadLibcall(ExpectedAddr.getPointer(), AO, IsVolatile);
1876f0ab553fSAlexey Bataev auto *ContBB = CGF.createBasicBlock("atomic_cont");
1877f0ab553fSAlexey Bataev auto *ExitBB = CGF.createBasicBlock("atomic_exit");
1878f0ab553fSAlexey Bataev CGF.EmitBlock(ContBB);
18797f416cc4SJohn McCall Address DesiredAddr = CreateTempAlloca();
1880f0ab553fSAlexey Bataev if ((LVal.isBitField() && BFI.Size != ValueSizeInBits) ||
18817f416cc4SJohn McCall requiresMemSetZero(getAtomicAddress().getElementType())) {
18827f416cc4SJohn McCall auto *OldVal = CGF.Builder.CreateLoad(ExpectedAddr);
18837f416cc4SJohn McCall CGF.Builder.CreateStore(OldVal, DesiredAddr);
1884f0ab553fSAlexey Bataev }
18857f416cc4SJohn McCall auto OldRVal = convertAtomicTempToRValue(ExpectedAddr,
18867f416cc4SJohn McCall AggValueSlot::ignored(),
1887f0ab553fSAlexey Bataev SourceLocation(), /*AsValue=*/false);
1888f0ab553fSAlexey Bataev EmitAtomicUpdateValue(CGF, *this, OldRVal, UpdateOp, DesiredAddr);
1889f0ab553fSAlexey Bataev auto *Res =
18907f416cc4SJohn McCall EmitAtomicCompareExchangeLibcall(ExpectedAddr.getPointer(),
18917f416cc4SJohn McCall DesiredAddr.getPointer(),
18927f416cc4SJohn McCall AO, Failure);
1893f0ab553fSAlexey Bataev CGF.Builder.CreateCondBr(Res, ExitBB, ContBB);
1894f0ab553fSAlexey Bataev CGF.EmitBlock(ExitBB, /*IsFinished=*/true);
1895f0ab553fSAlexey Bataev }
1896f0ab553fSAlexey Bataev
EmitAtomicUpdateOp(llvm::AtomicOrdering AO,const llvm::function_ref<RValue (RValue)> & UpdateOp,bool IsVolatile)1897f0ab553fSAlexey Bataev void AtomicInfo::EmitAtomicUpdateOp(
1898f0ab553fSAlexey Bataev llvm::AtomicOrdering AO, const llvm::function_ref<RValue(RValue)> &UpdateOp,
1899f0ab553fSAlexey Bataev bool IsVolatile) {
1900f0ab553fSAlexey Bataev auto Failure = llvm::AtomicCmpXchgInst::getStrongestFailureOrdering(AO);
1901f0ab553fSAlexey Bataev
1902f0ab553fSAlexey Bataev // Do the atomic load.
1903e8e05de0SAlexey Bataev auto *OldVal = EmitAtomicLoadOp(Failure, IsVolatile);
1904f0ab553fSAlexey Bataev // For non-simple lvalues perform compare-and-swap procedure.
1905f0ab553fSAlexey Bataev auto *ContBB = CGF.createBasicBlock("atomic_cont");
1906f0ab553fSAlexey Bataev auto *ExitBB = CGF.createBasicBlock("atomic_exit");
1907f0ab553fSAlexey Bataev auto *CurBB = CGF.Builder.GetInsertBlock();
1908f0ab553fSAlexey Bataev CGF.EmitBlock(ContBB);
1909f0ab553fSAlexey Bataev llvm::PHINode *PHI = CGF.Builder.CreatePHI(OldVal->getType(),
1910f0ab553fSAlexey Bataev /*NumReservedValues=*/2);
1911f0ab553fSAlexey Bataev PHI->addIncoming(OldVal, CurBB);
19127f416cc4SJohn McCall Address NewAtomicAddr = CreateTempAlloca();
19137f416cc4SJohn McCall Address NewAtomicIntAddr = emitCastToAtomicIntPointer(NewAtomicAddr);
1914f0ab553fSAlexey Bataev if ((LVal.isBitField() && BFI.Size != ValueSizeInBits) ||
19157f416cc4SJohn McCall requiresMemSetZero(getAtomicAddress().getElementType())) {
19167f416cc4SJohn McCall CGF.Builder.CreateStore(PHI, NewAtomicIntAddr);
1917f0ab553fSAlexey Bataev }
1918f0ab553fSAlexey Bataev auto OldRVal = ConvertIntToValueOrAtomic(PHI, AggValueSlot::ignored(),
1919f0ab553fSAlexey Bataev SourceLocation(), /*AsValue=*/false);
1920f0ab553fSAlexey Bataev EmitAtomicUpdateValue(CGF, *this, OldRVal, UpdateOp, NewAtomicAddr);
19217f416cc4SJohn McCall auto *DesiredVal = CGF.Builder.CreateLoad(NewAtomicIntAddr);
1922144a43a2SAmy Huang // Try to write new value using cmpxchg operation.
1923f0ab553fSAlexey Bataev auto Res = EmitAtomicCompareExchangeOp(PHI, DesiredVal, AO, Failure);
1924f0ab553fSAlexey Bataev PHI->addIncoming(Res.first, CGF.Builder.GetInsertBlock());
1925f0ab553fSAlexey Bataev CGF.Builder.CreateCondBr(Res.second, ExitBB, ContBB);
1926f0ab553fSAlexey Bataev CGF.EmitBlock(ExitBB, /*IsFinished=*/true);
1927f0ab553fSAlexey Bataev }
1928f0ab553fSAlexey Bataev
EmitAtomicUpdateValue(CodeGenFunction & CGF,AtomicInfo & Atomics,RValue UpdateRVal,Address DesiredAddr)1929f0ab553fSAlexey Bataev static void EmitAtomicUpdateValue(CodeGenFunction &CGF, AtomicInfo &Atomics,
19307f416cc4SJohn McCall RValue UpdateRVal, Address DesiredAddr) {
1931f0ab553fSAlexey Bataev LValue AtomicLVal = Atomics.getAtomicLValue();
1932f0ab553fSAlexey Bataev LValue DesiredLVal;
1933144a43a2SAmy Huang // Build new lvalue for temp address.
1934f0ab553fSAlexey Bataev if (AtomicLVal.isBitField()) {
1935f0ab553fSAlexey Bataev DesiredLVal =
1936f0ab553fSAlexey Bataev LValue::MakeBitfield(DesiredAddr, AtomicLVal.getBitFieldInfo(),
1937d17f12a3SIvan A. Kosarev AtomicLVal.getType(), AtomicLVal.getBaseInfo(),
1938d17f12a3SIvan A. Kosarev AtomicLVal.getTBAAInfo());
1939f0ab553fSAlexey Bataev } else if (AtomicLVal.isVectorElt()) {
1940f0ab553fSAlexey Bataev DesiredLVal =
1941f0ab553fSAlexey Bataev LValue::MakeVectorElt(DesiredAddr, AtomicLVal.getVectorIdx(),
1942d17f12a3SIvan A. Kosarev AtomicLVal.getType(), AtomicLVal.getBaseInfo(),
1943d17f12a3SIvan A. Kosarev AtomicLVal.getTBAAInfo());
1944f0ab553fSAlexey Bataev } else {
1945f0ab553fSAlexey Bataev assert(AtomicLVal.isExtVectorElt());
1946f0ab553fSAlexey Bataev DesiredLVal = LValue::MakeExtVectorElt(
1947f0ab553fSAlexey Bataev DesiredAddr, AtomicLVal.getExtVectorElts(), AtomicLVal.getType(),
1948d17f12a3SIvan A. Kosarev AtomicLVal.getBaseInfo(), AtomicLVal.getTBAAInfo());
1949f0ab553fSAlexey Bataev }
1950144a43a2SAmy Huang // Store new value in the corresponding memory area.
1951f0ab553fSAlexey Bataev assert(UpdateRVal.isScalar());
1952f0ab553fSAlexey Bataev CGF.EmitStoreThroughLValue(UpdateRVal, DesiredLVal);
1953f0ab553fSAlexey Bataev }
1954f0ab553fSAlexey Bataev
EmitAtomicUpdateLibcall(llvm::AtomicOrdering AO,RValue UpdateRVal,bool IsVolatile)1955f0ab553fSAlexey Bataev void AtomicInfo::EmitAtomicUpdateLibcall(llvm::AtomicOrdering AO,
1956f0ab553fSAlexey Bataev RValue UpdateRVal, bool IsVolatile) {
1957f0ab553fSAlexey Bataev auto Failure = llvm::AtomicCmpXchgInst::getStrongestFailureOrdering(AO);
1958f0ab553fSAlexey Bataev
19597f416cc4SJohn McCall Address ExpectedAddr = CreateTempAlloca();
1960f0ab553fSAlexey Bataev
19617f416cc4SJohn McCall EmitAtomicLoadLibcall(ExpectedAddr.getPointer(), AO, IsVolatile);
1962f0ab553fSAlexey Bataev auto *ContBB = CGF.createBasicBlock("atomic_cont");
1963f0ab553fSAlexey Bataev auto *ExitBB = CGF.createBasicBlock("atomic_exit");
1964f0ab553fSAlexey Bataev CGF.EmitBlock(ContBB);
19657f416cc4SJohn McCall Address DesiredAddr = CreateTempAlloca();
1966f0ab553fSAlexey Bataev if ((LVal.isBitField() && BFI.Size != ValueSizeInBits) ||
19677f416cc4SJohn McCall requiresMemSetZero(getAtomicAddress().getElementType())) {
19687f416cc4SJohn McCall auto *OldVal = CGF.Builder.CreateLoad(ExpectedAddr);
19697f416cc4SJohn McCall CGF.Builder.CreateStore(OldVal, DesiredAddr);
1970f0ab553fSAlexey Bataev }
1971f0ab553fSAlexey Bataev EmitAtomicUpdateValue(CGF, *this, UpdateRVal, DesiredAddr);
1972f0ab553fSAlexey Bataev auto *Res =
19737f416cc4SJohn McCall EmitAtomicCompareExchangeLibcall(ExpectedAddr.getPointer(),
19747f416cc4SJohn McCall DesiredAddr.getPointer(),
19757f416cc4SJohn McCall AO, Failure);
1976f0ab553fSAlexey Bataev CGF.Builder.CreateCondBr(Res, ExitBB, ContBB);
1977f0ab553fSAlexey Bataev CGF.EmitBlock(ExitBB, /*IsFinished=*/true);
1978f0ab553fSAlexey Bataev }
1979f0ab553fSAlexey Bataev
EmitAtomicUpdateOp(llvm::AtomicOrdering AO,RValue UpdateRVal,bool IsVolatile)1980f0ab553fSAlexey Bataev void AtomicInfo::EmitAtomicUpdateOp(llvm::AtomicOrdering AO, RValue UpdateRVal,
1981f0ab553fSAlexey Bataev bool IsVolatile) {
1982f0ab553fSAlexey Bataev auto Failure = llvm::AtomicCmpXchgInst::getStrongestFailureOrdering(AO);
1983f0ab553fSAlexey Bataev
1984f0ab553fSAlexey Bataev // Do the atomic load.
1985e8e05de0SAlexey Bataev auto *OldVal = EmitAtomicLoadOp(Failure, IsVolatile);
1986f0ab553fSAlexey Bataev // For non-simple lvalues perform compare-and-swap procedure.
1987f0ab553fSAlexey Bataev auto *ContBB = CGF.createBasicBlock("atomic_cont");
1988f0ab553fSAlexey Bataev auto *ExitBB = CGF.createBasicBlock("atomic_exit");
1989f0ab553fSAlexey Bataev auto *CurBB = CGF.Builder.GetInsertBlock();
1990f0ab553fSAlexey Bataev CGF.EmitBlock(ContBB);
1991f0ab553fSAlexey Bataev llvm::PHINode *PHI = CGF.Builder.CreatePHI(OldVal->getType(),
1992f0ab553fSAlexey Bataev /*NumReservedValues=*/2);
1993f0ab553fSAlexey Bataev PHI->addIncoming(OldVal, CurBB);
19947f416cc4SJohn McCall Address NewAtomicAddr = CreateTempAlloca();
19957f416cc4SJohn McCall Address NewAtomicIntAddr = emitCastToAtomicIntPointer(NewAtomicAddr);
1996f0ab553fSAlexey Bataev if ((LVal.isBitField() && BFI.Size != ValueSizeInBits) ||
19977f416cc4SJohn McCall requiresMemSetZero(getAtomicAddress().getElementType())) {
19987f416cc4SJohn McCall CGF.Builder.CreateStore(PHI, NewAtomicIntAddr);
1999f0ab553fSAlexey Bataev }
2000f0ab553fSAlexey Bataev EmitAtomicUpdateValue(CGF, *this, UpdateRVal, NewAtomicAddr);
20017f416cc4SJohn McCall auto *DesiredVal = CGF.Builder.CreateLoad(NewAtomicIntAddr);
2002144a43a2SAmy Huang // Try to write new value using cmpxchg operation.
2003f0ab553fSAlexey Bataev auto Res = EmitAtomicCompareExchangeOp(PHI, DesiredVal, AO, Failure);
2004f0ab553fSAlexey Bataev PHI->addIncoming(Res.first, CGF.Builder.GetInsertBlock());
2005f0ab553fSAlexey Bataev CGF.Builder.CreateCondBr(Res.second, ExitBB, ContBB);
2006f0ab553fSAlexey Bataev CGF.EmitBlock(ExitBB, /*IsFinished=*/true);
2007f0ab553fSAlexey Bataev }
2008f0ab553fSAlexey Bataev
EmitAtomicUpdate(llvm::AtomicOrdering AO,const llvm::function_ref<RValue (RValue)> & UpdateOp,bool IsVolatile)2009f0ab553fSAlexey Bataev void AtomicInfo::EmitAtomicUpdate(
2010f0ab553fSAlexey Bataev llvm::AtomicOrdering AO, const llvm::function_ref<RValue(RValue)> &UpdateOp,
2011f0ab553fSAlexey Bataev bool IsVolatile) {
2012f0ab553fSAlexey Bataev if (shouldUseLibcall()) {
2013f0ab553fSAlexey Bataev EmitAtomicUpdateLibcall(AO, UpdateOp, IsVolatile);
2014f0ab553fSAlexey Bataev } else {
2015f0ab553fSAlexey Bataev EmitAtomicUpdateOp(AO, UpdateOp, IsVolatile);
2016f0ab553fSAlexey Bataev }
2017f0ab553fSAlexey Bataev }
2018f0ab553fSAlexey Bataev
EmitAtomicUpdate(llvm::AtomicOrdering AO,RValue UpdateRVal,bool IsVolatile)2019f0ab553fSAlexey Bataev void AtomicInfo::EmitAtomicUpdate(llvm::AtomicOrdering AO, RValue UpdateRVal,
2020f0ab553fSAlexey Bataev bool IsVolatile) {
2021f0ab553fSAlexey Bataev if (shouldUseLibcall()) {
2022f0ab553fSAlexey Bataev EmitAtomicUpdateLibcall(AO, UpdateRVal, IsVolatile);
2023f0ab553fSAlexey Bataev } else {
2024f0ab553fSAlexey Bataev EmitAtomicUpdateOp(AO, UpdateRVal, IsVolatile);
2025f0ab553fSAlexey Bataev }
2026b8329261SAlexey Bataev }
2027b8329261SAlexey Bataev
EmitAtomicStore(RValue rvalue,LValue lvalue,bool isInit)2028a5b195a1SDavid Majnemer void CodeGenFunction::EmitAtomicStore(RValue rvalue, LValue lvalue,
2029a5b195a1SDavid Majnemer bool isInit) {
2030a5b195a1SDavid Majnemer bool IsVolatile = lvalue.isVolatileQualified();
2031a5b195a1SDavid Majnemer llvm::AtomicOrdering AO;
2032a5b195a1SDavid Majnemer if (lvalue.getType()->isAtomicType()) {
203392f4ef10SJF Bastien AO = llvm::AtomicOrdering::SequentiallyConsistent;
2034a5b195a1SDavid Majnemer } else {
203592f4ef10SJF Bastien AO = llvm::AtomicOrdering::Release;
2036a5b195a1SDavid Majnemer IsVolatile = true;
2037a5b195a1SDavid Majnemer }
2038a5b195a1SDavid Majnemer return EmitAtomicStore(rvalue, lvalue, AO, IsVolatile, isInit);
2039a5b195a1SDavid Majnemer }
2040a5b195a1SDavid Majnemer
2041a8ec7eb9SJohn McCall /// Emit a store to an l-value of atomic type.
2042a8ec7eb9SJohn McCall ///
2043a8ec7eb9SJohn McCall /// Note that the r-value is expected to be an r-value *of the atomic
2044a8ec7eb9SJohn McCall /// type*; this means that for aggregate r-values, it should include
2045a8ec7eb9SJohn McCall /// storage for any padding that was necessary.
EmitAtomicStore(RValue rvalue,LValue dest,llvm::AtomicOrdering AO,bool IsVolatile,bool isInit)2046a5b195a1SDavid Majnemer void CodeGenFunction::EmitAtomicStore(RValue rvalue, LValue dest,
2047a5b195a1SDavid Majnemer llvm::AtomicOrdering AO, bool IsVolatile,
2048a5b195a1SDavid Majnemer bool isInit) {
2049a8ec7eb9SJohn McCall // If this is an aggregate r-value, it should agree in type except
2050a8ec7eb9SJohn McCall // maybe for address-space qualification.
2051a8ec7eb9SJohn McCall assert(!rvalue.isAggregate() ||
2052f139ae3dSAkira Hatanaka rvalue.getAggregateAddress().getElementType() ==
2053f139ae3dSAkira Hatanaka dest.getAddress(*this).getElementType());
2054a8ec7eb9SJohn McCall
2055a8ec7eb9SJohn McCall AtomicInfo atomics(*this, dest);
2056b8329261SAlexey Bataev LValue LVal = atomics.getAtomicLValue();
2057a8ec7eb9SJohn McCall
2058a8ec7eb9SJohn McCall // If this is an initialization, just put the value there normally.
2059b8329261SAlexey Bataev if (LVal.isSimple()) {
2060a8ec7eb9SJohn McCall if (isInit) {
2061b57056f4SAlexey Bataev atomics.emitCopyIntoMemory(rvalue);
2062a8ec7eb9SJohn McCall return;
2063a8ec7eb9SJohn McCall }
2064a8ec7eb9SJohn McCall
2065a8ec7eb9SJohn McCall // Check whether we should use a library call.
2066a8ec7eb9SJohn McCall if (atomics.shouldUseLibcall()) {
2067a8ec7eb9SJohn McCall // Produce a source address.
20687f416cc4SJohn McCall Address srcAddr = atomics.materializeRValue(rvalue);
2069a8ec7eb9SJohn McCall
2070a8ec7eb9SJohn McCall // void __atomic_store(size_t size, void *mem, void *val, int order)
2071a8ec7eb9SJohn McCall CallArgList args;
2072a8ec7eb9SJohn McCall args.add(RValue::get(atomics.getAtomicSizeValue()),
2073a8ec7eb9SJohn McCall getContext().getSizeType());
20747f416cc4SJohn McCall args.add(RValue::get(EmitCastToVoidPtr(atomics.getAtomicPointer())),
2075a8ec7eb9SJohn McCall getContext().VoidPtrTy);
20767f416cc4SJohn McCall args.add(RValue::get(EmitCastToVoidPtr(srcAddr.getPointer())),
20777f416cc4SJohn McCall getContext().VoidPtrTy);
2078dda2cb17SJF Bastien args.add(
2079dda2cb17SJF Bastien RValue::get(llvm::ConstantInt::get(IntTy, (int)llvm::toCABI(AO))),
2080a8ec7eb9SJohn McCall getContext().IntTy);
2081a8ec7eb9SJohn McCall emitAtomicLibcall(*this, "__atomic_store", getContext().VoidTy, args);
2082a8ec7eb9SJohn McCall return;
2083a8ec7eb9SJohn McCall }
2084a8ec7eb9SJohn McCall
2085a8ec7eb9SJohn McCall // Okay, we're doing this natively.
2086452d8e11SAlexey Bataev llvm::Value *intValue = atomics.convertRValueToInt(rvalue);
2087a8ec7eb9SJohn McCall
2088a8ec7eb9SJohn McCall // Do the atomic store.
20897f416cc4SJohn McCall Address addr =
2090b8329261SAlexey Bataev atomics.emitCastToAtomicIntPointer(atomics.getAtomicAddress());
2091b8329261SAlexey Bataev intValue = Builder.CreateIntCast(
20927f416cc4SJohn McCall intValue, addr.getElementType(), /*isSigned=*/false);
2093a8ec7eb9SJohn McCall llvm::StoreInst *store = Builder.CreateStore(intValue, addr);
2094a8ec7eb9SJohn McCall
2095e8e05de0SAlexey Bataev if (AO == llvm::AtomicOrdering::Acquire)
2096e8e05de0SAlexey Bataev AO = llvm::AtomicOrdering::Monotonic;
2097e8e05de0SAlexey Bataev else if (AO == llvm::AtomicOrdering::AcquireRelease)
2098e8e05de0SAlexey Bataev AO = llvm::AtomicOrdering::Release;
2099a8ec7eb9SJohn McCall // Initializations don't need to be atomic.
2100b8329261SAlexey Bataev if (!isInit)
2101b8329261SAlexey Bataev store->setAtomic(AO);
2102a8ec7eb9SJohn McCall
2103a8ec7eb9SJohn McCall // Other decoration.
2104a5b195a1SDavid Majnemer if (IsVolatile)
2105a8ec7eb9SJohn McCall store->setVolatile(true);
2106383890baSIvan A. Kosarev CGM.DecorateInstructionWithTBAA(store, dest.getTBAAInfo());
2107b8329261SAlexey Bataev return;
2108b8329261SAlexey Bataev }
2109b8329261SAlexey Bataev
2110f0ab553fSAlexey Bataev // Emit simple atomic update operation.
2111f0ab553fSAlexey Bataev atomics.EmitAtomicUpdate(AO, rvalue, IsVolatile);
2112a8ec7eb9SJohn McCall }
2113a8ec7eb9SJohn McCall
2114452d8e11SAlexey Bataev /// Emit a compare-and-exchange op for atomic type.
2115452d8e11SAlexey Bataev ///
EmitAtomicCompareExchange(LValue Obj,RValue Expected,RValue Desired,SourceLocation Loc,llvm::AtomicOrdering Success,llvm::AtomicOrdering Failure,bool IsWeak,AggValueSlot Slot)2116b4505a72SAlexey Bataev std::pair<RValue, llvm::Value *> CodeGenFunction::EmitAtomicCompareExchange(
2117452d8e11SAlexey Bataev LValue Obj, RValue Expected, RValue Desired, SourceLocation Loc,
2118452d8e11SAlexey Bataev llvm::AtomicOrdering Success, llvm::AtomicOrdering Failure, bool IsWeak,
2119452d8e11SAlexey Bataev AggValueSlot Slot) {
2120452d8e11SAlexey Bataev // If this is an aggregate r-value, it should agree in type except
2121452d8e11SAlexey Bataev // maybe for address-space qualification.
2122452d8e11SAlexey Bataev assert(!Expected.isAggregate() ||
21237f416cc4SJohn McCall Expected.getAggregateAddress().getElementType() ==
2124f139ae3dSAkira Hatanaka Obj.getAddress(*this).getElementType());
2125452d8e11SAlexey Bataev assert(!Desired.isAggregate() ||
21267f416cc4SJohn McCall Desired.getAggregateAddress().getElementType() ==
2127f139ae3dSAkira Hatanaka Obj.getAddress(*this).getElementType());
2128452d8e11SAlexey Bataev AtomicInfo Atomics(*this, Obj);
2129452d8e11SAlexey Bataev
2130b4505a72SAlexey Bataev return Atomics.EmitAtomicCompareExchange(Expected, Desired, Success, Failure,
2131b4505a72SAlexey Bataev IsWeak);
2132b4505a72SAlexey Bataev }
2133b4505a72SAlexey Bataev
EmitAtomicUpdate(LValue LVal,llvm::AtomicOrdering AO,const llvm::function_ref<RValue (RValue)> & UpdateOp,bool IsVolatile)2134b4505a72SAlexey Bataev void CodeGenFunction::EmitAtomicUpdate(
2135b4505a72SAlexey Bataev LValue LVal, llvm::AtomicOrdering AO,
2136f0ab553fSAlexey Bataev const llvm::function_ref<RValue(RValue)> &UpdateOp, bool IsVolatile) {
2137b4505a72SAlexey Bataev AtomicInfo Atomics(*this, LVal);
2138f0ab553fSAlexey Bataev Atomics.EmitAtomicUpdate(AO, UpdateOp, IsVolatile);
2139452d8e11SAlexey Bataev }
2140452d8e11SAlexey Bataev
EmitAtomicInit(Expr * init,LValue dest)2141a8ec7eb9SJohn McCall void CodeGenFunction::EmitAtomicInit(Expr *init, LValue dest) {
2142a8ec7eb9SJohn McCall AtomicInfo atomics(*this, dest);
2143a8ec7eb9SJohn McCall
2144a8ec7eb9SJohn McCall switch (atomics.getEvaluationKind()) {
2145a8ec7eb9SJohn McCall case TEK_Scalar: {
2146a8ec7eb9SJohn McCall llvm::Value *value = EmitScalarExpr(init);
2147b57056f4SAlexey Bataev atomics.emitCopyIntoMemory(RValue::get(value));
2148a8ec7eb9SJohn McCall return;
2149a8ec7eb9SJohn McCall }
2150a8ec7eb9SJohn McCall
2151a8ec7eb9SJohn McCall case TEK_Complex: {
2152a8ec7eb9SJohn McCall ComplexPairTy value = EmitComplexExpr(init);
2153b57056f4SAlexey Bataev atomics.emitCopyIntoMemory(RValue::getComplex(value));
2154a8ec7eb9SJohn McCall return;
2155a8ec7eb9SJohn McCall }
2156a8ec7eb9SJohn McCall
2157a8ec7eb9SJohn McCall case TEK_Aggregate: {
2158be4504dfSEli Friedman // Fix up the destination if the initializer isn't an expression
2159be4504dfSEli Friedman // of atomic type.
2160be4504dfSEli Friedman bool Zeroed = false;
2161a8ec7eb9SJohn McCall if (!init->getType()->isAtomicType()) {
2162b57056f4SAlexey Bataev Zeroed = atomics.emitMemSetZeroIfNecessary();
2163b57056f4SAlexey Bataev dest = atomics.projectValue();
2164a8ec7eb9SJohn McCall }
2165a8ec7eb9SJohn McCall
2166a8ec7eb9SJohn McCall // Evaluate the expression directly into the destination.
2167f139ae3dSAkira Hatanaka AggValueSlot slot = AggValueSlot::forLValue(
2168f139ae3dSAkira Hatanaka dest, *this, AggValueSlot::IsNotDestructed,
2169f139ae3dSAkira Hatanaka AggValueSlot::DoesNotNeedGCBarriers, AggValueSlot::IsNotAliased,
2170e78fac51SRichard Smith AggValueSlot::DoesNotOverlap,
2171f139ae3dSAkira Hatanaka Zeroed ? AggValueSlot::IsZeroed : AggValueSlot::IsNotZeroed);
2172be4504dfSEli Friedman
2173a8ec7eb9SJohn McCall EmitAggExpr(init, slot);
2174a8ec7eb9SJohn McCall return;
2175a8ec7eb9SJohn McCall }
2176a8ec7eb9SJohn McCall }
2177a8ec7eb9SJohn McCall llvm_unreachable("bad evaluation kind");
2178a8ec7eb9SJohn McCall }
2179