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