xref: /freebsd-src/contrib/llvm-project/clang/lib/CodeGen/CGAtomic.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
10b57cec5SDimitry Andric //===--- CGAtomic.cpp - Emit LLVM IR for atomic operations ----------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file contains the code for emitting atomic operations.
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric 
130b57cec5SDimitry Andric #include "CGCall.h"
140b57cec5SDimitry Andric #include "CGRecordLayout.h"
150b57cec5SDimitry Andric #include "CodeGenFunction.h"
160b57cec5SDimitry Andric #include "CodeGenModule.h"
170b57cec5SDimitry Andric #include "TargetInfo.h"
180b57cec5SDimitry Andric #include "clang/AST/ASTContext.h"
190b57cec5SDimitry Andric #include "clang/CodeGen/CGFunctionInfo.h"
200b57cec5SDimitry Andric #include "clang/Frontend/FrontendDiagnostic.h"
210b57cec5SDimitry Andric #include "llvm/ADT/DenseMap.h"
220b57cec5SDimitry Andric #include "llvm/IR/DataLayout.h"
230b57cec5SDimitry Andric #include "llvm/IR/Intrinsics.h"
240b57cec5SDimitry Andric #include "llvm/IR/Operator.h"
250b57cec5SDimitry Andric 
260b57cec5SDimitry Andric using namespace clang;
270b57cec5SDimitry Andric using namespace CodeGen;
280b57cec5SDimitry Andric 
290b57cec5SDimitry Andric namespace {
300b57cec5SDimitry Andric   class AtomicInfo {
310b57cec5SDimitry Andric     CodeGenFunction &CGF;
320b57cec5SDimitry Andric     QualType AtomicTy;
330b57cec5SDimitry Andric     QualType ValueTy;
340b57cec5SDimitry Andric     uint64_t AtomicSizeInBits;
350b57cec5SDimitry Andric     uint64_t ValueSizeInBits;
360b57cec5SDimitry Andric     CharUnits AtomicAlign;
370b57cec5SDimitry Andric     CharUnits ValueAlign;
380b57cec5SDimitry Andric     TypeEvaluationKind EvaluationKind;
390b57cec5SDimitry Andric     bool UseLibcall;
400b57cec5SDimitry Andric     LValue LVal;
410b57cec5SDimitry Andric     CGBitFieldInfo BFI;
420b57cec5SDimitry Andric   public:
430b57cec5SDimitry Andric     AtomicInfo(CodeGenFunction &CGF, LValue &lvalue)
440b57cec5SDimitry Andric         : CGF(CGF), AtomicSizeInBits(0), ValueSizeInBits(0),
450b57cec5SDimitry Andric           EvaluationKind(TEK_Scalar), UseLibcall(true) {
460b57cec5SDimitry Andric       assert(!lvalue.isGlobalReg());
470b57cec5SDimitry Andric       ASTContext &C = CGF.getContext();
480b57cec5SDimitry Andric       if (lvalue.isSimple()) {
490b57cec5SDimitry Andric         AtomicTy = lvalue.getType();
500b57cec5SDimitry Andric         if (auto *ATy = AtomicTy->getAs<AtomicType>())
510b57cec5SDimitry Andric           ValueTy = ATy->getValueType();
520b57cec5SDimitry Andric         else
530b57cec5SDimitry Andric           ValueTy = AtomicTy;
540b57cec5SDimitry Andric         EvaluationKind = CGF.getEvaluationKind(ValueTy);
550b57cec5SDimitry Andric 
560b57cec5SDimitry Andric         uint64_t ValueAlignInBits;
570b57cec5SDimitry Andric         uint64_t AtomicAlignInBits;
580b57cec5SDimitry Andric         TypeInfo ValueTI = C.getTypeInfo(ValueTy);
590b57cec5SDimitry Andric         ValueSizeInBits = ValueTI.Width;
600b57cec5SDimitry Andric         ValueAlignInBits = ValueTI.Align;
610b57cec5SDimitry Andric 
620b57cec5SDimitry Andric         TypeInfo AtomicTI = C.getTypeInfo(AtomicTy);
630b57cec5SDimitry Andric         AtomicSizeInBits = AtomicTI.Width;
640b57cec5SDimitry Andric         AtomicAlignInBits = AtomicTI.Align;
650b57cec5SDimitry Andric 
660b57cec5SDimitry Andric         assert(ValueSizeInBits <= AtomicSizeInBits);
670b57cec5SDimitry Andric         assert(ValueAlignInBits <= AtomicAlignInBits);
680b57cec5SDimitry Andric 
690b57cec5SDimitry Andric         AtomicAlign = C.toCharUnitsFromBits(AtomicAlignInBits);
700b57cec5SDimitry Andric         ValueAlign = C.toCharUnitsFromBits(ValueAlignInBits);
710b57cec5SDimitry Andric         if (lvalue.getAlignment().isZero())
720b57cec5SDimitry Andric           lvalue.setAlignment(AtomicAlign);
730b57cec5SDimitry Andric 
740b57cec5SDimitry Andric         LVal = lvalue;
750b57cec5SDimitry Andric       } else if (lvalue.isBitField()) {
760b57cec5SDimitry Andric         ValueTy = lvalue.getType();
770b57cec5SDimitry Andric         ValueSizeInBits = C.getTypeSize(ValueTy);
780b57cec5SDimitry Andric         auto &OrigBFI = lvalue.getBitFieldInfo();
790b57cec5SDimitry Andric         auto Offset = OrigBFI.Offset % C.toBits(lvalue.getAlignment());
800b57cec5SDimitry Andric         AtomicSizeInBits = C.toBits(
810b57cec5SDimitry Andric             C.toCharUnitsFromBits(Offset + OrigBFI.Size + C.getCharWidth() - 1)
820b57cec5SDimitry Andric                 .alignTo(lvalue.getAlignment()));
83*0fca6ea1SDimitry Andric         llvm::Value *BitFieldPtr = lvalue.getRawBitFieldPointer(CGF);
840b57cec5SDimitry Andric         auto OffsetInChars =
850b57cec5SDimitry Andric             (C.toCharUnitsFromBits(OrigBFI.Offset) / lvalue.getAlignment()) *
860b57cec5SDimitry Andric             lvalue.getAlignment();
8706c3fb27SDimitry Andric         llvm::Value *StoragePtr = CGF.Builder.CreateConstGEP1_64(
8806c3fb27SDimitry Andric             CGF.Int8Ty, BitFieldPtr, OffsetInChars.getQuantity());
8906c3fb27SDimitry Andric         StoragePtr = CGF.Builder.CreateAddrSpaceCast(
905f757f3fSDimitry Andric             StoragePtr, CGF.UnqualPtrTy, "atomic_bitfield_base");
910b57cec5SDimitry Andric         BFI = OrigBFI;
920b57cec5SDimitry Andric         BFI.Offset = Offset;
930b57cec5SDimitry Andric         BFI.StorageSize = AtomicSizeInBits;
940b57cec5SDimitry Andric         BFI.StorageOffset += OffsetInChars;
9506c3fb27SDimitry Andric         llvm::Type *StorageTy = CGF.Builder.getIntNTy(AtomicSizeInBits);
9606c3fb27SDimitry Andric         LVal = LValue::MakeBitfield(
9706c3fb27SDimitry Andric             Address(StoragePtr, StorageTy, lvalue.getAlignment()), BFI,
9806c3fb27SDimitry Andric             lvalue.getType(), lvalue.getBaseInfo(), lvalue.getTBAAInfo());
990b57cec5SDimitry Andric         AtomicTy = C.getIntTypeForBitwidth(AtomicSizeInBits, OrigBFI.IsSigned);
1000b57cec5SDimitry Andric         if (AtomicTy.isNull()) {
1010b57cec5SDimitry Andric           llvm::APInt Size(
1020b57cec5SDimitry Andric               /*numBits=*/32,
1030b57cec5SDimitry Andric               C.toCharUnitsFromBits(AtomicSizeInBits).getQuantity());
1045f757f3fSDimitry Andric           AtomicTy = C.getConstantArrayType(C.CharTy, Size, nullptr,
1055f757f3fSDimitry Andric                                             ArraySizeModifier::Normal,
1060b57cec5SDimitry Andric                                             /*IndexTypeQuals=*/0);
1070b57cec5SDimitry Andric         }
1080b57cec5SDimitry Andric         AtomicAlign = ValueAlign = lvalue.getAlignment();
1090b57cec5SDimitry Andric       } else if (lvalue.isVectorElt()) {
110a7dea167SDimitry Andric         ValueTy = lvalue.getType()->castAs<VectorType>()->getElementType();
1110b57cec5SDimitry Andric         ValueSizeInBits = C.getTypeSize(ValueTy);
1120b57cec5SDimitry Andric         AtomicTy = lvalue.getType();
1130b57cec5SDimitry Andric         AtomicSizeInBits = C.getTypeSize(AtomicTy);
1140b57cec5SDimitry Andric         AtomicAlign = ValueAlign = lvalue.getAlignment();
1150b57cec5SDimitry Andric         LVal = lvalue;
1160b57cec5SDimitry Andric       } else {
1170b57cec5SDimitry Andric         assert(lvalue.isExtVectorElt());
1180b57cec5SDimitry Andric         ValueTy = lvalue.getType();
1190b57cec5SDimitry Andric         ValueSizeInBits = C.getTypeSize(ValueTy);
1200b57cec5SDimitry Andric         AtomicTy = ValueTy = CGF.getContext().getExtVectorType(
121e8d8bef9SDimitry Andric             lvalue.getType(), cast<llvm::FixedVectorType>(
1225ffd83dbSDimitry Andric                                   lvalue.getExtVectorAddress().getElementType())
1235ffd83dbSDimitry Andric                                   ->getNumElements());
1240b57cec5SDimitry Andric         AtomicSizeInBits = C.getTypeSize(AtomicTy);
1250b57cec5SDimitry Andric         AtomicAlign = ValueAlign = lvalue.getAlignment();
1260b57cec5SDimitry Andric         LVal = lvalue;
1270b57cec5SDimitry Andric       }
1280b57cec5SDimitry Andric       UseLibcall = !C.getTargetInfo().hasBuiltinAtomic(
1290b57cec5SDimitry Andric           AtomicSizeInBits, C.toBits(lvalue.getAlignment()));
1300b57cec5SDimitry Andric     }
1310b57cec5SDimitry Andric 
1320b57cec5SDimitry Andric     QualType getAtomicType() const { return AtomicTy; }
1330b57cec5SDimitry Andric     QualType getValueType() const { return ValueTy; }
1340b57cec5SDimitry Andric     CharUnits getAtomicAlignment() const { return AtomicAlign; }
1350b57cec5SDimitry Andric     uint64_t getAtomicSizeInBits() const { return AtomicSizeInBits; }
1360b57cec5SDimitry Andric     uint64_t getValueSizeInBits() const { return ValueSizeInBits; }
1370b57cec5SDimitry Andric     TypeEvaluationKind getEvaluationKind() const { return EvaluationKind; }
1380b57cec5SDimitry Andric     bool shouldUseLibcall() const { return UseLibcall; }
1390b57cec5SDimitry Andric     const LValue &getAtomicLValue() const { return LVal; }
1400b57cec5SDimitry Andric     llvm::Value *getAtomicPointer() const {
1410b57cec5SDimitry Andric       if (LVal.isSimple())
142*0fca6ea1SDimitry Andric         return LVal.emitRawPointer(CGF);
1430b57cec5SDimitry Andric       else if (LVal.isBitField())
144*0fca6ea1SDimitry Andric         return LVal.getRawBitFieldPointer(CGF);
1450b57cec5SDimitry Andric       else if (LVal.isVectorElt())
146*0fca6ea1SDimitry Andric         return LVal.getRawVectorPointer(CGF);
1470b57cec5SDimitry Andric       assert(LVal.isExtVectorElt());
148*0fca6ea1SDimitry Andric       return LVal.getRawExtVectorPointer(CGF);
1490b57cec5SDimitry Andric     }
1500b57cec5SDimitry Andric     Address getAtomicAddress() const {
15181ad6265SDimitry Andric       llvm::Type *ElTy;
15281ad6265SDimitry Andric       if (LVal.isSimple())
153*0fca6ea1SDimitry Andric         ElTy = LVal.getAddress().getElementType();
15481ad6265SDimitry Andric       else if (LVal.isBitField())
15581ad6265SDimitry Andric         ElTy = LVal.getBitFieldAddress().getElementType();
15681ad6265SDimitry Andric       else if (LVal.isVectorElt())
15781ad6265SDimitry Andric         ElTy = LVal.getVectorAddress().getElementType();
15881ad6265SDimitry Andric       else
15981ad6265SDimitry Andric         ElTy = LVal.getExtVectorAddress().getElementType();
16081ad6265SDimitry Andric       return Address(getAtomicPointer(), ElTy, getAtomicAlignment());
1610b57cec5SDimitry Andric     }
1620b57cec5SDimitry Andric 
1630b57cec5SDimitry Andric     Address getAtomicAddressAsAtomicIntPointer() const {
16406c3fb27SDimitry Andric       return castToAtomicIntPointer(getAtomicAddress());
1650b57cec5SDimitry Andric     }
1660b57cec5SDimitry Andric 
1670b57cec5SDimitry Andric     /// Is the atomic size larger than the underlying value type?
1680b57cec5SDimitry Andric     ///
1690b57cec5SDimitry Andric     /// Note that the absence of padding does not mean that atomic
1700b57cec5SDimitry Andric     /// objects are completely interchangeable with non-atomic
1710b57cec5SDimitry Andric     /// objects: we might have promoted the alignment of a type
1720b57cec5SDimitry Andric     /// without making it bigger.
1730b57cec5SDimitry Andric     bool hasPadding() const {
1740b57cec5SDimitry Andric       return (ValueSizeInBits != AtomicSizeInBits);
1750b57cec5SDimitry Andric     }
1760b57cec5SDimitry Andric 
1770b57cec5SDimitry Andric     bool emitMemSetZeroIfNecessary() const;
1780b57cec5SDimitry Andric 
1790b57cec5SDimitry Andric     llvm::Value *getAtomicSizeValue() const {
1800b57cec5SDimitry Andric       CharUnits size = CGF.getContext().toCharUnitsFromBits(AtomicSizeInBits);
1810b57cec5SDimitry Andric       return CGF.CGM.getSize(size);
1820b57cec5SDimitry Andric     }
1830b57cec5SDimitry Andric 
1840b57cec5SDimitry Andric     /// Cast the given pointer to an integer pointer suitable for atomic
1850b57cec5SDimitry Andric     /// operations if the source.
18606c3fb27SDimitry Andric     Address castToAtomicIntPointer(Address Addr) const;
1870b57cec5SDimitry Andric 
1880b57cec5SDimitry Andric     /// If Addr is compatible with the iN that will be used for an atomic
1890b57cec5SDimitry Andric     /// operation, bitcast it. Otherwise, create a temporary that is suitable
1900b57cec5SDimitry Andric     /// and copy the value across.
1910b57cec5SDimitry Andric     Address convertToAtomicIntPointer(Address Addr) const;
1920b57cec5SDimitry Andric 
1930b57cec5SDimitry Andric     /// Turn an atomic-layout object into an r-value.
1940b57cec5SDimitry Andric     RValue convertAtomicTempToRValue(Address addr, AggValueSlot resultSlot,
1950b57cec5SDimitry Andric                                      SourceLocation loc, bool AsValue) const;
1960b57cec5SDimitry Andric 
197*0fca6ea1SDimitry Andric     llvm::Value *getScalarRValValueOrNull(RValue RVal) const;
1980b57cec5SDimitry Andric 
199*0fca6ea1SDimitry Andric     /// Converts an rvalue to integer value if needed.
200*0fca6ea1SDimitry Andric     llvm::Value *convertRValueToInt(RValue RVal, bool CmpXchg = false) const;
201*0fca6ea1SDimitry Andric 
202*0fca6ea1SDimitry Andric     RValue ConvertToValueOrAtomic(llvm::Value *IntVal, AggValueSlot ResultSlot,
203*0fca6ea1SDimitry Andric                                   SourceLocation Loc, bool AsValue,
204*0fca6ea1SDimitry Andric                                   bool CmpXchg = false) const;
2050b57cec5SDimitry Andric 
2060b57cec5SDimitry Andric     /// Copy an atomic r-value into atomic-layout memory.
2070b57cec5SDimitry Andric     void emitCopyIntoMemory(RValue rvalue) const;
2080b57cec5SDimitry Andric 
2090b57cec5SDimitry Andric     /// Project an l-value down to the value field.
2100b57cec5SDimitry Andric     LValue projectValue() const {
2110b57cec5SDimitry Andric       assert(LVal.isSimple());
2120b57cec5SDimitry Andric       Address addr = getAtomicAddress();
2130b57cec5SDimitry Andric       if (hasPadding())
2140b57cec5SDimitry Andric         addr = CGF.Builder.CreateStructGEP(addr, 0);
2150b57cec5SDimitry Andric 
2160b57cec5SDimitry Andric       return LValue::MakeAddr(addr, getValueType(), CGF.getContext(),
2170b57cec5SDimitry Andric                               LVal.getBaseInfo(), LVal.getTBAAInfo());
2180b57cec5SDimitry Andric     }
2190b57cec5SDimitry Andric 
2200b57cec5SDimitry Andric     /// Emits atomic load.
2210b57cec5SDimitry Andric     /// \returns Loaded value.
2220b57cec5SDimitry Andric     RValue EmitAtomicLoad(AggValueSlot ResultSlot, SourceLocation Loc,
2230b57cec5SDimitry Andric                           bool AsValue, llvm::AtomicOrdering AO,
2240b57cec5SDimitry Andric                           bool IsVolatile);
2250b57cec5SDimitry Andric 
2260b57cec5SDimitry Andric     /// Emits atomic compare-and-exchange sequence.
2270b57cec5SDimitry Andric     /// \param Expected Expected value.
2280b57cec5SDimitry Andric     /// \param Desired Desired value.
2290b57cec5SDimitry Andric     /// \param Success Atomic ordering for success operation.
2300b57cec5SDimitry Andric     /// \param Failure Atomic ordering for failed operation.
2310b57cec5SDimitry Andric     /// \param IsWeak true if atomic operation is weak, false otherwise.
2320b57cec5SDimitry Andric     /// \returns Pair of values: previous value from storage (value type) and
2330b57cec5SDimitry Andric     /// boolean flag (i1 type) with true if success and false otherwise.
2340b57cec5SDimitry Andric     std::pair<RValue, llvm::Value *>
2350b57cec5SDimitry Andric     EmitAtomicCompareExchange(RValue Expected, RValue Desired,
2360b57cec5SDimitry Andric                               llvm::AtomicOrdering Success =
2370b57cec5SDimitry Andric                                   llvm::AtomicOrdering::SequentiallyConsistent,
2380b57cec5SDimitry Andric                               llvm::AtomicOrdering Failure =
2390b57cec5SDimitry Andric                                   llvm::AtomicOrdering::SequentiallyConsistent,
2400b57cec5SDimitry Andric                               bool IsWeak = false);
2410b57cec5SDimitry Andric 
2420b57cec5SDimitry Andric     /// Emits atomic update.
2430b57cec5SDimitry Andric     /// \param AO Atomic ordering.
2440b57cec5SDimitry Andric     /// \param UpdateOp Update operation for the current lvalue.
2450b57cec5SDimitry Andric     void EmitAtomicUpdate(llvm::AtomicOrdering AO,
2460b57cec5SDimitry Andric                           const llvm::function_ref<RValue(RValue)> &UpdateOp,
2470b57cec5SDimitry Andric                           bool IsVolatile);
2480b57cec5SDimitry Andric     /// Emits atomic update.
2490b57cec5SDimitry Andric     /// \param AO Atomic ordering.
2500b57cec5SDimitry Andric     void EmitAtomicUpdate(llvm::AtomicOrdering AO, RValue UpdateRVal,
2510b57cec5SDimitry Andric                           bool IsVolatile);
2520b57cec5SDimitry Andric 
2530b57cec5SDimitry Andric     /// Materialize an atomic r-value in atomic-layout memory.
2540b57cec5SDimitry Andric     Address materializeRValue(RValue rvalue) const;
2550b57cec5SDimitry Andric 
2560b57cec5SDimitry Andric     /// Creates temp alloca for intermediate operations on atomic value.
2570b57cec5SDimitry Andric     Address CreateTempAlloca() const;
2580b57cec5SDimitry Andric   private:
2590b57cec5SDimitry Andric     bool requiresMemSetZero(llvm::Type *type) const;
2600b57cec5SDimitry Andric 
2610b57cec5SDimitry Andric 
2620b57cec5SDimitry Andric     /// Emits atomic load as a libcall.
2630b57cec5SDimitry Andric     void EmitAtomicLoadLibcall(llvm::Value *AddForLoaded,
2640b57cec5SDimitry Andric                                llvm::AtomicOrdering AO, bool IsVolatile);
2650b57cec5SDimitry Andric     /// Emits atomic load as LLVM instruction.
266*0fca6ea1SDimitry Andric     llvm::Value *EmitAtomicLoadOp(llvm::AtomicOrdering AO, bool IsVolatile,
267*0fca6ea1SDimitry Andric                                   bool CmpXchg = false);
2680b57cec5SDimitry Andric     /// Emits atomic compare-and-exchange op as a libcall.
2690b57cec5SDimitry Andric     llvm::Value *EmitAtomicCompareExchangeLibcall(
2700b57cec5SDimitry Andric         llvm::Value *ExpectedAddr, llvm::Value *DesiredAddr,
2710b57cec5SDimitry Andric         llvm::AtomicOrdering Success =
2720b57cec5SDimitry Andric             llvm::AtomicOrdering::SequentiallyConsistent,
2730b57cec5SDimitry Andric         llvm::AtomicOrdering Failure =
2740b57cec5SDimitry Andric             llvm::AtomicOrdering::SequentiallyConsistent);
2750b57cec5SDimitry Andric     /// Emits atomic compare-and-exchange op as LLVM instruction.
2760b57cec5SDimitry Andric     std::pair<llvm::Value *, llvm::Value *> EmitAtomicCompareExchangeOp(
2770b57cec5SDimitry Andric         llvm::Value *ExpectedVal, llvm::Value *DesiredVal,
2780b57cec5SDimitry Andric         llvm::AtomicOrdering Success =
2790b57cec5SDimitry Andric             llvm::AtomicOrdering::SequentiallyConsistent,
2800b57cec5SDimitry Andric         llvm::AtomicOrdering Failure =
2810b57cec5SDimitry Andric             llvm::AtomicOrdering::SequentiallyConsistent,
2820b57cec5SDimitry Andric         bool IsWeak = false);
2830b57cec5SDimitry Andric     /// Emit atomic update as libcalls.
2840b57cec5SDimitry Andric     void
2850b57cec5SDimitry Andric     EmitAtomicUpdateLibcall(llvm::AtomicOrdering AO,
2860b57cec5SDimitry Andric                             const llvm::function_ref<RValue(RValue)> &UpdateOp,
2870b57cec5SDimitry Andric                             bool IsVolatile);
2880b57cec5SDimitry Andric     /// Emit atomic update as LLVM instructions.
2890b57cec5SDimitry Andric     void EmitAtomicUpdateOp(llvm::AtomicOrdering AO,
2900b57cec5SDimitry Andric                             const llvm::function_ref<RValue(RValue)> &UpdateOp,
2910b57cec5SDimitry Andric                             bool IsVolatile);
2920b57cec5SDimitry Andric     /// Emit atomic update as libcalls.
2930b57cec5SDimitry Andric     void EmitAtomicUpdateLibcall(llvm::AtomicOrdering AO, RValue UpdateRVal,
2940b57cec5SDimitry Andric                                  bool IsVolatile);
2950b57cec5SDimitry Andric     /// Emit atomic update as LLVM instructions.
2960b57cec5SDimitry Andric     void EmitAtomicUpdateOp(llvm::AtomicOrdering AO, RValue UpdateRal,
2970b57cec5SDimitry Andric                             bool IsVolatile);
2980b57cec5SDimitry Andric   };
2990b57cec5SDimitry Andric }
3000b57cec5SDimitry Andric 
3010b57cec5SDimitry Andric Address AtomicInfo::CreateTempAlloca() const {
3020b57cec5SDimitry Andric   Address TempAlloca = CGF.CreateMemTemp(
3030b57cec5SDimitry Andric       (LVal.isBitField() && ValueSizeInBits > AtomicSizeInBits) ? ValueTy
3040b57cec5SDimitry Andric                                                                 : AtomicTy,
3050b57cec5SDimitry Andric       getAtomicAlignment(),
3060b57cec5SDimitry Andric       "atomic-temp");
3070b57cec5SDimitry Andric   // Cast to pointer to value type for bitfields.
3080b57cec5SDimitry Andric   if (LVal.isBitField())
3090b57cec5SDimitry Andric     return CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
31081ad6265SDimitry Andric         TempAlloca, getAtomicAddress().getType(),
31181ad6265SDimitry Andric         getAtomicAddress().getElementType());
3120b57cec5SDimitry Andric   return TempAlloca;
3130b57cec5SDimitry Andric }
3140b57cec5SDimitry Andric 
3150b57cec5SDimitry Andric static RValue emitAtomicLibcall(CodeGenFunction &CGF,
3160b57cec5SDimitry Andric                                 StringRef fnName,
3170b57cec5SDimitry Andric                                 QualType resultType,
3180b57cec5SDimitry Andric                                 CallArgList &args) {
3190b57cec5SDimitry Andric   const CGFunctionInfo &fnInfo =
3200b57cec5SDimitry Andric     CGF.CGM.getTypes().arrangeBuiltinFunctionCall(resultType, args);
3210b57cec5SDimitry Andric   llvm::FunctionType *fnTy = CGF.CGM.getTypes().GetFunctionType(fnInfo);
32204eeddc0SDimitry Andric   llvm::AttrBuilder fnAttrB(CGF.getLLVMContext());
323e8d8bef9SDimitry Andric   fnAttrB.addAttribute(llvm::Attribute::NoUnwind);
324e8d8bef9SDimitry Andric   fnAttrB.addAttribute(llvm::Attribute::WillReturn);
325e8d8bef9SDimitry Andric   llvm::AttributeList fnAttrs = llvm::AttributeList::get(
326e8d8bef9SDimitry Andric       CGF.getLLVMContext(), llvm::AttributeList::FunctionIndex, fnAttrB);
327e8d8bef9SDimitry Andric 
328e8d8bef9SDimitry Andric   llvm::FunctionCallee fn =
329e8d8bef9SDimitry Andric       CGF.CGM.CreateRuntimeFunction(fnTy, fnName, fnAttrs);
3300b57cec5SDimitry Andric   auto callee = CGCallee::forDirect(fn);
3310b57cec5SDimitry Andric   return CGF.EmitCall(fnInfo, callee, ReturnValueSlot(), args);
3320b57cec5SDimitry Andric }
3330b57cec5SDimitry Andric 
3340b57cec5SDimitry Andric /// Does a store of the given IR type modify the full expected width?
3350b57cec5SDimitry Andric static bool isFullSizeType(CodeGenModule &CGM, llvm::Type *type,
3360b57cec5SDimitry Andric                            uint64_t expectedSize) {
3370b57cec5SDimitry Andric   return (CGM.getDataLayout().getTypeStoreSize(type) * 8 == expectedSize);
3380b57cec5SDimitry Andric }
3390b57cec5SDimitry Andric 
3400b57cec5SDimitry Andric /// Does the atomic type require memsetting to zero before initialization?
3410b57cec5SDimitry Andric ///
3420b57cec5SDimitry Andric /// The IR type is provided as a way of making certain queries faster.
3430b57cec5SDimitry Andric bool AtomicInfo::requiresMemSetZero(llvm::Type *type) const {
3440b57cec5SDimitry Andric   // If the atomic type has size padding, we definitely need a memset.
3450b57cec5SDimitry Andric   if (hasPadding()) return true;
3460b57cec5SDimitry Andric 
3470b57cec5SDimitry Andric   // Otherwise, do some simple heuristics to try to avoid it:
3480b57cec5SDimitry Andric   switch (getEvaluationKind()) {
3490b57cec5SDimitry Andric   // For scalars and complexes, check whether the store size of the
3500b57cec5SDimitry Andric   // type uses the full size.
3510b57cec5SDimitry Andric   case TEK_Scalar:
3520b57cec5SDimitry Andric     return !isFullSizeType(CGF.CGM, type, AtomicSizeInBits);
3530b57cec5SDimitry Andric   case TEK_Complex:
3540b57cec5SDimitry Andric     return !isFullSizeType(CGF.CGM, type->getStructElementType(0),
3550b57cec5SDimitry Andric                            AtomicSizeInBits / 2);
3560b57cec5SDimitry Andric 
3570b57cec5SDimitry Andric   // Padding in structs has an undefined bit pattern.  User beware.
3580b57cec5SDimitry Andric   case TEK_Aggregate:
3590b57cec5SDimitry Andric     return false;
3600b57cec5SDimitry Andric   }
3610b57cec5SDimitry Andric   llvm_unreachable("bad evaluation kind");
3620b57cec5SDimitry Andric }
3630b57cec5SDimitry Andric 
3640b57cec5SDimitry Andric bool AtomicInfo::emitMemSetZeroIfNecessary() const {
3650b57cec5SDimitry Andric   assert(LVal.isSimple());
366*0fca6ea1SDimitry Andric   Address addr = LVal.getAddress();
36704eeddc0SDimitry Andric   if (!requiresMemSetZero(addr.getElementType()))
3680b57cec5SDimitry Andric     return false;
3690b57cec5SDimitry Andric 
3700b57cec5SDimitry Andric   CGF.Builder.CreateMemSet(
371*0fca6ea1SDimitry Andric       addr.emitRawPointer(CGF), llvm::ConstantInt::get(CGF.Int8Ty, 0),
3720b57cec5SDimitry Andric       CGF.getContext().toCharUnitsFromBits(AtomicSizeInBits).getQuantity(),
373480093f4SDimitry Andric       LVal.getAlignment().getAsAlign());
3740b57cec5SDimitry Andric   return true;
3750b57cec5SDimitry Andric }
3760b57cec5SDimitry Andric 
3770b57cec5SDimitry Andric static void emitAtomicCmpXchg(CodeGenFunction &CGF, AtomicExpr *E, bool IsWeak,
3780b57cec5SDimitry Andric                               Address Dest, Address Ptr,
3790b57cec5SDimitry Andric                               Address Val1, Address Val2,
3800b57cec5SDimitry Andric                               uint64_t Size,
3810b57cec5SDimitry Andric                               llvm::AtomicOrdering SuccessOrder,
3820b57cec5SDimitry Andric                               llvm::AtomicOrdering FailureOrder,
3830b57cec5SDimitry Andric                               llvm::SyncScope::ID Scope) {
3840b57cec5SDimitry Andric   // Note that cmpxchg doesn't support weak cmpxchg, at least at the moment.
3850b57cec5SDimitry Andric   llvm::Value *Expected = CGF.Builder.CreateLoad(Val1);
3860b57cec5SDimitry Andric   llvm::Value *Desired = CGF.Builder.CreateLoad(Val2);
3870b57cec5SDimitry Andric 
3880b57cec5SDimitry Andric   llvm::AtomicCmpXchgInst *Pair = CGF.Builder.CreateAtomicCmpXchg(
3895f757f3fSDimitry Andric       Ptr, Expected, Desired, SuccessOrder, FailureOrder, Scope);
3900b57cec5SDimitry Andric   Pair->setVolatile(E->isVolatile());
3910b57cec5SDimitry Andric   Pair->setWeak(IsWeak);
3920b57cec5SDimitry Andric 
3930b57cec5SDimitry Andric   // Cmp holds the result of the compare-exchange operation: true on success,
3940b57cec5SDimitry Andric   // false on failure.
3950b57cec5SDimitry Andric   llvm::Value *Old = CGF.Builder.CreateExtractValue(Pair, 0);
3960b57cec5SDimitry Andric   llvm::Value *Cmp = CGF.Builder.CreateExtractValue(Pair, 1);
3970b57cec5SDimitry Andric 
3980b57cec5SDimitry Andric   // This basic block is used to hold the store instruction if the operation
3990b57cec5SDimitry Andric   // failed.
4000b57cec5SDimitry Andric   llvm::BasicBlock *StoreExpectedBB =
4010b57cec5SDimitry Andric       CGF.createBasicBlock("cmpxchg.store_expected", CGF.CurFn);
4020b57cec5SDimitry Andric 
4030b57cec5SDimitry Andric   // This basic block is the exit point of the operation, we should end up
4040b57cec5SDimitry Andric   // here regardless of whether or not the operation succeeded.
4050b57cec5SDimitry Andric   llvm::BasicBlock *ContinueBB =
4060b57cec5SDimitry Andric       CGF.createBasicBlock("cmpxchg.continue", CGF.CurFn);
4070b57cec5SDimitry Andric 
4080b57cec5SDimitry Andric   // Update Expected if Expected isn't equal to Old, otherwise branch to the
4090b57cec5SDimitry Andric   // exit point.
4100b57cec5SDimitry Andric   CGF.Builder.CreateCondBr(Cmp, ContinueBB, StoreExpectedBB);
4110b57cec5SDimitry Andric 
4120b57cec5SDimitry Andric   CGF.Builder.SetInsertPoint(StoreExpectedBB);
4130b57cec5SDimitry Andric   // Update the memory at Expected with Old's value.
4140b57cec5SDimitry Andric   CGF.Builder.CreateStore(Old, Val1);
4150b57cec5SDimitry Andric   // Finally, branch to the exit point.
4160b57cec5SDimitry Andric   CGF.Builder.CreateBr(ContinueBB);
4170b57cec5SDimitry Andric 
4180b57cec5SDimitry Andric   CGF.Builder.SetInsertPoint(ContinueBB);
4190b57cec5SDimitry Andric   // Update the memory at Dest with Cmp's value.
4200b57cec5SDimitry Andric   CGF.EmitStoreOfScalar(Cmp, CGF.MakeAddrLValue(Dest, E->getType()));
4210b57cec5SDimitry Andric }
4220b57cec5SDimitry Andric 
4230b57cec5SDimitry Andric /// Given an ordering required on success, emit all possible cmpxchg
4240b57cec5SDimitry Andric /// instructions to cope with the provided (but possibly only dynamically known)
4250b57cec5SDimitry Andric /// FailureOrder.
4260b57cec5SDimitry Andric static void emitAtomicCmpXchgFailureSet(CodeGenFunction &CGF, AtomicExpr *E,
4270b57cec5SDimitry Andric                                         bool IsWeak, Address Dest, Address Ptr,
4280b57cec5SDimitry Andric                                         Address Val1, Address Val2,
4290b57cec5SDimitry Andric                                         llvm::Value *FailureOrderVal,
4300b57cec5SDimitry Andric                                         uint64_t Size,
4310b57cec5SDimitry Andric                                         llvm::AtomicOrdering SuccessOrder,
4320b57cec5SDimitry Andric                                         llvm::SyncScope::ID Scope) {
4330b57cec5SDimitry Andric   llvm::AtomicOrdering FailureOrder;
4340b57cec5SDimitry Andric   if (llvm::ConstantInt *FO = dyn_cast<llvm::ConstantInt>(FailureOrderVal)) {
4350b57cec5SDimitry Andric     auto FOS = FO->getSExtValue();
4360b57cec5SDimitry Andric     if (!llvm::isValidAtomicOrderingCABI(FOS))
4370b57cec5SDimitry Andric       FailureOrder = llvm::AtomicOrdering::Monotonic;
4380b57cec5SDimitry Andric     else
4390b57cec5SDimitry Andric       switch ((llvm::AtomicOrderingCABI)FOS) {
4400b57cec5SDimitry Andric       case llvm::AtomicOrderingCABI::relaxed:
441fe6060f1SDimitry Andric       // 31.7.2.18: "The failure argument shall not be memory_order_release
442fe6060f1SDimitry Andric       // nor memory_order_acq_rel". Fallback to monotonic.
4430b57cec5SDimitry Andric       case llvm::AtomicOrderingCABI::release:
4440b57cec5SDimitry Andric       case llvm::AtomicOrderingCABI::acq_rel:
4450b57cec5SDimitry Andric         FailureOrder = llvm::AtomicOrdering::Monotonic;
4460b57cec5SDimitry Andric         break;
4470b57cec5SDimitry Andric       case llvm::AtomicOrderingCABI::consume:
4480b57cec5SDimitry Andric       case llvm::AtomicOrderingCABI::acquire:
4490b57cec5SDimitry Andric         FailureOrder = llvm::AtomicOrdering::Acquire;
4500b57cec5SDimitry Andric         break;
4510b57cec5SDimitry Andric       case llvm::AtomicOrderingCABI::seq_cst:
4520b57cec5SDimitry Andric         FailureOrder = llvm::AtomicOrdering::SequentiallyConsistent;
4530b57cec5SDimitry Andric         break;
4540b57cec5SDimitry Andric       }
455fe6060f1SDimitry Andric     // Prior to c++17, "the failure argument shall be no stronger than the
456fe6060f1SDimitry Andric     // success argument". This condition has been lifted and the only
457fe6060f1SDimitry Andric     // precondition is 31.7.2.18. Effectively treat this as a DR and skip
458fe6060f1SDimitry Andric     // language version checks.
4590b57cec5SDimitry Andric     emitAtomicCmpXchg(CGF, E, IsWeak, Dest, Ptr, Val1, Val2, Size, SuccessOrder,
4600b57cec5SDimitry Andric                       FailureOrder, Scope);
4610b57cec5SDimitry Andric     return;
4620b57cec5SDimitry Andric   }
4630b57cec5SDimitry Andric 
4640b57cec5SDimitry Andric   // Create all the relevant BB's
465fe6060f1SDimitry Andric   auto *MonotonicBB = CGF.createBasicBlock("monotonic_fail", CGF.CurFn);
466fe6060f1SDimitry Andric   auto *AcquireBB = CGF.createBasicBlock("acquire_fail", CGF.CurFn);
467fe6060f1SDimitry Andric   auto *SeqCstBB = CGF.createBasicBlock("seqcst_fail", CGF.CurFn);
468fe6060f1SDimitry Andric   auto *ContBB = CGF.createBasicBlock("atomic.continue", CGF.CurFn);
4690b57cec5SDimitry Andric 
4700b57cec5SDimitry Andric   // MonotonicBB is arbitrarily chosen as the default case; in practice, this
4710b57cec5SDimitry Andric   // doesn't matter unless someone is crazy enough to use something that
4720b57cec5SDimitry Andric   // doesn't fold to a constant for the ordering.
473fe6060f1SDimitry Andric   llvm::SwitchInst *SI = CGF.Builder.CreateSwitch(FailureOrderVal, MonotonicBB);
474fe6060f1SDimitry Andric   // Implemented as acquire, since it's the closest in LLVM.
475fe6060f1SDimitry Andric   SI->addCase(CGF.Builder.getInt32((int)llvm::AtomicOrderingCABI::consume),
476fe6060f1SDimitry Andric               AcquireBB);
477fe6060f1SDimitry Andric   SI->addCase(CGF.Builder.getInt32((int)llvm::AtomicOrderingCABI::acquire),
478fe6060f1SDimitry Andric               AcquireBB);
479fe6060f1SDimitry Andric   SI->addCase(CGF.Builder.getInt32((int)llvm::AtomicOrderingCABI::seq_cst),
480fe6060f1SDimitry Andric               SeqCstBB);
481fe6060f1SDimitry Andric 
482fe6060f1SDimitry Andric   // Emit all the different atomics
4830b57cec5SDimitry Andric   CGF.Builder.SetInsertPoint(MonotonicBB);
4840b57cec5SDimitry Andric   emitAtomicCmpXchg(CGF, E, IsWeak, Dest, Ptr, Val1, Val2,
4850b57cec5SDimitry Andric                     Size, SuccessOrder, llvm::AtomicOrdering::Monotonic, Scope);
4860b57cec5SDimitry Andric   CGF.Builder.CreateBr(ContBB);
4870b57cec5SDimitry Andric 
4880b57cec5SDimitry Andric   CGF.Builder.SetInsertPoint(AcquireBB);
489fe6060f1SDimitry Andric   emitAtomicCmpXchg(CGF, E, IsWeak, Dest, Ptr, Val1, Val2, Size, SuccessOrder,
490fe6060f1SDimitry Andric                     llvm::AtomicOrdering::Acquire, Scope);
4910b57cec5SDimitry Andric   CGF.Builder.CreateBr(ContBB);
492fe6060f1SDimitry Andric 
4930b57cec5SDimitry Andric   CGF.Builder.SetInsertPoint(SeqCstBB);
4940b57cec5SDimitry Andric   emitAtomicCmpXchg(CGF, E, IsWeak, Dest, Ptr, Val1, Val2, Size, SuccessOrder,
4950b57cec5SDimitry Andric                     llvm::AtomicOrdering::SequentiallyConsistent, Scope);
4960b57cec5SDimitry Andric   CGF.Builder.CreateBr(ContBB);
4970b57cec5SDimitry Andric 
4980b57cec5SDimitry Andric   CGF.Builder.SetInsertPoint(ContBB);
4990b57cec5SDimitry Andric }
5000b57cec5SDimitry Andric 
501480093f4SDimitry Andric /// Duplicate the atomic min/max operation in conventional IR for the builtin
502480093f4SDimitry Andric /// variants that return the new rather than the original value.
503480093f4SDimitry Andric static llvm::Value *EmitPostAtomicMinMax(CGBuilderTy &Builder,
504480093f4SDimitry Andric                                          AtomicExpr::AtomicOp Op,
505480093f4SDimitry Andric                                          bool IsSigned,
506480093f4SDimitry Andric                                          llvm::Value *OldVal,
507480093f4SDimitry Andric                                          llvm::Value *RHS) {
508480093f4SDimitry Andric   llvm::CmpInst::Predicate Pred;
509480093f4SDimitry Andric   switch (Op) {
510480093f4SDimitry Andric   default:
511480093f4SDimitry Andric     llvm_unreachable("Unexpected min/max operation");
512480093f4SDimitry Andric   case AtomicExpr::AO__atomic_max_fetch:
5135f757f3fSDimitry Andric   case AtomicExpr::AO__scoped_atomic_max_fetch:
514480093f4SDimitry Andric     Pred = IsSigned ? llvm::CmpInst::ICMP_SGT : llvm::CmpInst::ICMP_UGT;
515480093f4SDimitry Andric     break;
516480093f4SDimitry Andric   case AtomicExpr::AO__atomic_min_fetch:
5175f757f3fSDimitry Andric   case AtomicExpr::AO__scoped_atomic_min_fetch:
518480093f4SDimitry Andric     Pred = IsSigned ? llvm::CmpInst::ICMP_SLT : llvm::CmpInst::ICMP_ULT;
519480093f4SDimitry Andric     break;
520480093f4SDimitry Andric   }
521480093f4SDimitry Andric   llvm::Value *Cmp = Builder.CreateICmp(Pred, OldVal, RHS, "tst");
522480093f4SDimitry Andric   return Builder.CreateSelect(Cmp, OldVal, RHS, "newval");
523480093f4SDimitry Andric }
524480093f4SDimitry Andric 
5250b57cec5SDimitry Andric static void EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *E, Address Dest,
5260b57cec5SDimitry Andric                          Address Ptr, Address Val1, Address Val2,
5270b57cec5SDimitry Andric                          llvm::Value *IsWeak, llvm::Value *FailureOrder,
5280b57cec5SDimitry Andric                          uint64_t Size, llvm::AtomicOrdering Order,
5290b57cec5SDimitry Andric                          llvm::SyncScope::ID Scope) {
5300b57cec5SDimitry Andric   llvm::AtomicRMWInst::BinOp Op = llvm::AtomicRMWInst::Add;
531480093f4SDimitry Andric   bool PostOpMinMax = false;
532480093f4SDimitry Andric   unsigned PostOp = 0;
5330b57cec5SDimitry Andric 
5340b57cec5SDimitry Andric   switch (E->getOp()) {
5350b57cec5SDimitry Andric   case AtomicExpr::AO__c11_atomic_init:
5360b57cec5SDimitry Andric   case AtomicExpr::AO__opencl_atomic_init:
5370b57cec5SDimitry Andric     llvm_unreachable("Already handled!");
5380b57cec5SDimitry Andric 
5390b57cec5SDimitry Andric   case AtomicExpr::AO__c11_atomic_compare_exchange_strong:
5404824e7fdSDimitry Andric   case AtomicExpr::AO__hip_atomic_compare_exchange_strong:
5410b57cec5SDimitry Andric   case AtomicExpr::AO__opencl_atomic_compare_exchange_strong:
5420b57cec5SDimitry Andric     emitAtomicCmpXchgFailureSet(CGF, E, false, Dest, Ptr, Val1, Val2,
5430b57cec5SDimitry Andric                                 FailureOrder, Size, Order, Scope);
5440b57cec5SDimitry Andric     return;
5450b57cec5SDimitry Andric   case AtomicExpr::AO__c11_atomic_compare_exchange_weak:
5460b57cec5SDimitry Andric   case AtomicExpr::AO__opencl_atomic_compare_exchange_weak:
5474824e7fdSDimitry Andric   case AtomicExpr::AO__hip_atomic_compare_exchange_weak:
5480b57cec5SDimitry Andric     emitAtomicCmpXchgFailureSet(CGF, E, true, Dest, Ptr, Val1, Val2,
5490b57cec5SDimitry Andric                                 FailureOrder, Size, Order, Scope);
5500b57cec5SDimitry Andric     return;
5510b57cec5SDimitry Andric   case AtomicExpr::AO__atomic_compare_exchange:
5525f757f3fSDimitry Andric   case AtomicExpr::AO__atomic_compare_exchange_n:
5535f757f3fSDimitry Andric   case AtomicExpr::AO__scoped_atomic_compare_exchange:
5545f757f3fSDimitry Andric   case AtomicExpr::AO__scoped_atomic_compare_exchange_n: {
5550b57cec5SDimitry Andric     if (llvm::ConstantInt *IsWeakC = dyn_cast<llvm::ConstantInt>(IsWeak)) {
5560b57cec5SDimitry Andric       emitAtomicCmpXchgFailureSet(CGF, E, IsWeakC->getZExtValue(), Dest, Ptr,
5570b57cec5SDimitry Andric                                   Val1, Val2, FailureOrder, Size, Order, Scope);
5580b57cec5SDimitry Andric     } else {
5590b57cec5SDimitry Andric       // Create all the relevant BB's
5600b57cec5SDimitry Andric       llvm::BasicBlock *StrongBB =
5610b57cec5SDimitry Andric           CGF.createBasicBlock("cmpxchg.strong", CGF.CurFn);
5620b57cec5SDimitry Andric       llvm::BasicBlock *WeakBB = CGF.createBasicBlock("cmxchg.weak", CGF.CurFn);
5630b57cec5SDimitry Andric       llvm::BasicBlock *ContBB =
5640b57cec5SDimitry Andric           CGF.createBasicBlock("cmpxchg.continue", CGF.CurFn);
5650b57cec5SDimitry Andric 
5660b57cec5SDimitry Andric       llvm::SwitchInst *SI = CGF.Builder.CreateSwitch(IsWeak, WeakBB);
5670b57cec5SDimitry Andric       SI->addCase(CGF.Builder.getInt1(false), StrongBB);
5680b57cec5SDimitry Andric 
5690b57cec5SDimitry Andric       CGF.Builder.SetInsertPoint(StrongBB);
5700b57cec5SDimitry Andric       emitAtomicCmpXchgFailureSet(CGF, E, false, Dest, Ptr, Val1, Val2,
5710b57cec5SDimitry Andric                                   FailureOrder, Size, Order, Scope);
5720b57cec5SDimitry Andric       CGF.Builder.CreateBr(ContBB);
5730b57cec5SDimitry Andric 
5740b57cec5SDimitry Andric       CGF.Builder.SetInsertPoint(WeakBB);
5750b57cec5SDimitry Andric       emitAtomicCmpXchgFailureSet(CGF, E, true, Dest, Ptr, Val1, Val2,
5760b57cec5SDimitry Andric                                   FailureOrder, Size, Order, Scope);
5770b57cec5SDimitry Andric       CGF.Builder.CreateBr(ContBB);
5780b57cec5SDimitry Andric 
5790b57cec5SDimitry Andric       CGF.Builder.SetInsertPoint(ContBB);
5800b57cec5SDimitry Andric     }
5810b57cec5SDimitry Andric     return;
5820b57cec5SDimitry Andric   }
5830b57cec5SDimitry Andric   case AtomicExpr::AO__c11_atomic_load:
5840b57cec5SDimitry Andric   case AtomicExpr::AO__opencl_atomic_load:
5854824e7fdSDimitry Andric   case AtomicExpr::AO__hip_atomic_load:
5860b57cec5SDimitry Andric   case AtomicExpr::AO__atomic_load_n:
5875f757f3fSDimitry Andric   case AtomicExpr::AO__atomic_load:
5885f757f3fSDimitry Andric   case AtomicExpr::AO__scoped_atomic_load_n:
5895f757f3fSDimitry Andric   case AtomicExpr::AO__scoped_atomic_load: {
5900b57cec5SDimitry Andric     llvm::LoadInst *Load = CGF.Builder.CreateLoad(Ptr);
5910b57cec5SDimitry Andric     Load->setAtomic(Order, Scope);
5920b57cec5SDimitry Andric     Load->setVolatile(E->isVolatile());
5930b57cec5SDimitry Andric     CGF.Builder.CreateStore(Load, Dest);
5940b57cec5SDimitry Andric     return;
5950b57cec5SDimitry Andric   }
5960b57cec5SDimitry Andric 
5970b57cec5SDimitry Andric   case AtomicExpr::AO__c11_atomic_store:
5980b57cec5SDimitry Andric   case AtomicExpr::AO__opencl_atomic_store:
5994824e7fdSDimitry Andric   case AtomicExpr::AO__hip_atomic_store:
6000b57cec5SDimitry Andric   case AtomicExpr::AO__atomic_store:
6015f757f3fSDimitry Andric   case AtomicExpr::AO__atomic_store_n:
6025f757f3fSDimitry Andric   case AtomicExpr::AO__scoped_atomic_store:
6035f757f3fSDimitry Andric   case AtomicExpr::AO__scoped_atomic_store_n: {
6040b57cec5SDimitry Andric     llvm::Value *LoadVal1 = CGF.Builder.CreateLoad(Val1);
6050b57cec5SDimitry Andric     llvm::StoreInst *Store = CGF.Builder.CreateStore(LoadVal1, Ptr);
6060b57cec5SDimitry Andric     Store->setAtomic(Order, Scope);
6070b57cec5SDimitry Andric     Store->setVolatile(E->isVolatile());
6080b57cec5SDimitry Andric     return;
6090b57cec5SDimitry Andric   }
6100b57cec5SDimitry Andric 
6110b57cec5SDimitry Andric   case AtomicExpr::AO__c11_atomic_exchange:
6124824e7fdSDimitry Andric   case AtomicExpr::AO__hip_atomic_exchange:
6130b57cec5SDimitry Andric   case AtomicExpr::AO__opencl_atomic_exchange:
6140b57cec5SDimitry Andric   case AtomicExpr::AO__atomic_exchange_n:
6150b57cec5SDimitry Andric   case AtomicExpr::AO__atomic_exchange:
6165f757f3fSDimitry Andric   case AtomicExpr::AO__scoped_atomic_exchange_n:
6175f757f3fSDimitry Andric   case AtomicExpr::AO__scoped_atomic_exchange:
6180b57cec5SDimitry Andric     Op = llvm::AtomicRMWInst::Xchg;
6190b57cec5SDimitry Andric     break;
6200b57cec5SDimitry Andric 
6210b57cec5SDimitry Andric   case AtomicExpr::AO__atomic_add_fetch:
6225f757f3fSDimitry Andric   case AtomicExpr::AO__scoped_atomic_add_fetch:
623fe6060f1SDimitry Andric     PostOp = E->getValueType()->isFloatingType() ? llvm::Instruction::FAdd
624fe6060f1SDimitry Andric                                                  : llvm::Instruction::Add;
625bdd1243dSDimitry Andric     [[fallthrough]];
6260b57cec5SDimitry Andric   case AtomicExpr::AO__c11_atomic_fetch_add:
6274824e7fdSDimitry Andric   case AtomicExpr::AO__hip_atomic_fetch_add:
6280b57cec5SDimitry Andric   case AtomicExpr::AO__opencl_atomic_fetch_add:
6290b57cec5SDimitry Andric   case AtomicExpr::AO__atomic_fetch_add:
6305f757f3fSDimitry Andric   case AtomicExpr::AO__scoped_atomic_fetch_add:
631fe6060f1SDimitry Andric     Op = E->getValueType()->isFloatingType() ? llvm::AtomicRMWInst::FAdd
632fe6060f1SDimitry Andric                                              : llvm::AtomicRMWInst::Add;
6330b57cec5SDimitry Andric     break;
6340b57cec5SDimitry Andric 
6350b57cec5SDimitry Andric   case AtomicExpr::AO__atomic_sub_fetch:
6365f757f3fSDimitry Andric   case AtomicExpr::AO__scoped_atomic_sub_fetch:
637fe6060f1SDimitry Andric     PostOp = E->getValueType()->isFloatingType() ? llvm::Instruction::FSub
638fe6060f1SDimitry Andric                                                  : llvm::Instruction::Sub;
639bdd1243dSDimitry Andric     [[fallthrough]];
6400b57cec5SDimitry Andric   case AtomicExpr::AO__c11_atomic_fetch_sub:
64106c3fb27SDimitry Andric   case AtomicExpr::AO__hip_atomic_fetch_sub:
6420b57cec5SDimitry Andric   case AtomicExpr::AO__opencl_atomic_fetch_sub:
6430b57cec5SDimitry Andric   case AtomicExpr::AO__atomic_fetch_sub:
6445f757f3fSDimitry Andric   case AtomicExpr::AO__scoped_atomic_fetch_sub:
645fe6060f1SDimitry Andric     Op = E->getValueType()->isFloatingType() ? llvm::AtomicRMWInst::FSub
646fe6060f1SDimitry Andric                                              : llvm::AtomicRMWInst::Sub;
6470b57cec5SDimitry Andric     break;
6480b57cec5SDimitry Andric 
649480093f4SDimitry Andric   case AtomicExpr::AO__atomic_min_fetch:
6505f757f3fSDimitry Andric   case AtomicExpr::AO__scoped_atomic_min_fetch:
651480093f4SDimitry Andric     PostOpMinMax = true;
652bdd1243dSDimitry Andric     [[fallthrough]];
653480093f4SDimitry Andric   case AtomicExpr::AO__c11_atomic_fetch_min:
6544824e7fdSDimitry Andric   case AtomicExpr::AO__hip_atomic_fetch_min:
6550b57cec5SDimitry Andric   case AtomicExpr::AO__opencl_atomic_fetch_min:
6560b57cec5SDimitry Andric   case AtomicExpr::AO__atomic_fetch_min:
6575f757f3fSDimitry Andric   case AtomicExpr::AO__scoped_atomic_fetch_min:
65806c3fb27SDimitry Andric     Op = E->getValueType()->isFloatingType()
65906c3fb27SDimitry Andric              ? llvm::AtomicRMWInst::FMin
66006c3fb27SDimitry Andric              : (E->getValueType()->isSignedIntegerType()
66106c3fb27SDimitry Andric                     ? llvm::AtomicRMWInst::Min
66206c3fb27SDimitry Andric                     : llvm::AtomicRMWInst::UMin);
6630b57cec5SDimitry Andric     break;
6640b57cec5SDimitry Andric 
665480093f4SDimitry Andric   case AtomicExpr::AO__atomic_max_fetch:
6665f757f3fSDimitry Andric   case AtomicExpr::AO__scoped_atomic_max_fetch:
667480093f4SDimitry Andric     PostOpMinMax = true;
668bdd1243dSDimitry Andric     [[fallthrough]];
669480093f4SDimitry Andric   case AtomicExpr::AO__c11_atomic_fetch_max:
6704824e7fdSDimitry Andric   case AtomicExpr::AO__hip_atomic_fetch_max:
6710b57cec5SDimitry Andric   case AtomicExpr::AO__opencl_atomic_fetch_max:
6720b57cec5SDimitry Andric   case AtomicExpr::AO__atomic_fetch_max:
6735f757f3fSDimitry Andric   case AtomicExpr::AO__scoped_atomic_fetch_max:
67406c3fb27SDimitry Andric     Op = E->getValueType()->isFloatingType()
67506c3fb27SDimitry Andric              ? llvm::AtomicRMWInst::FMax
67606c3fb27SDimitry Andric              : (E->getValueType()->isSignedIntegerType()
67706c3fb27SDimitry Andric                     ? llvm::AtomicRMWInst::Max
67806c3fb27SDimitry Andric                     : llvm::AtomicRMWInst::UMax);
6790b57cec5SDimitry Andric     break;
6800b57cec5SDimitry Andric 
6810b57cec5SDimitry Andric   case AtomicExpr::AO__atomic_and_fetch:
6825f757f3fSDimitry Andric   case AtomicExpr::AO__scoped_atomic_and_fetch:
6830b57cec5SDimitry Andric     PostOp = llvm::Instruction::And;
684bdd1243dSDimitry Andric     [[fallthrough]];
6850b57cec5SDimitry Andric   case AtomicExpr::AO__c11_atomic_fetch_and:
6864824e7fdSDimitry Andric   case AtomicExpr::AO__hip_atomic_fetch_and:
6870b57cec5SDimitry Andric   case AtomicExpr::AO__opencl_atomic_fetch_and:
6880b57cec5SDimitry Andric   case AtomicExpr::AO__atomic_fetch_and:
6895f757f3fSDimitry Andric   case AtomicExpr::AO__scoped_atomic_fetch_and:
6900b57cec5SDimitry Andric     Op = llvm::AtomicRMWInst::And;
6910b57cec5SDimitry Andric     break;
6920b57cec5SDimitry Andric 
6930b57cec5SDimitry Andric   case AtomicExpr::AO__atomic_or_fetch:
6945f757f3fSDimitry Andric   case AtomicExpr::AO__scoped_atomic_or_fetch:
6950b57cec5SDimitry Andric     PostOp = llvm::Instruction::Or;
696bdd1243dSDimitry Andric     [[fallthrough]];
6970b57cec5SDimitry Andric   case AtomicExpr::AO__c11_atomic_fetch_or:
6984824e7fdSDimitry Andric   case AtomicExpr::AO__hip_atomic_fetch_or:
6990b57cec5SDimitry Andric   case AtomicExpr::AO__opencl_atomic_fetch_or:
7000b57cec5SDimitry Andric   case AtomicExpr::AO__atomic_fetch_or:
7015f757f3fSDimitry Andric   case AtomicExpr::AO__scoped_atomic_fetch_or:
7020b57cec5SDimitry Andric     Op = llvm::AtomicRMWInst::Or;
7030b57cec5SDimitry Andric     break;
7040b57cec5SDimitry Andric 
7050b57cec5SDimitry Andric   case AtomicExpr::AO__atomic_xor_fetch:
7065f757f3fSDimitry Andric   case AtomicExpr::AO__scoped_atomic_xor_fetch:
7070b57cec5SDimitry Andric     PostOp = llvm::Instruction::Xor;
708bdd1243dSDimitry Andric     [[fallthrough]];
7090b57cec5SDimitry Andric   case AtomicExpr::AO__c11_atomic_fetch_xor:
7104824e7fdSDimitry Andric   case AtomicExpr::AO__hip_atomic_fetch_xor:
7110b57cec5SDimitry Andric   case AtomicExpr::AO__opencl_atomic_fetch_xor:
7120b57cec5SDimitry Andric   case AtomicExpr::AO__atomic_fetch_xor:
7135f757f3fSDimitry Andric   case AtomicExpr::AO__scoped_atomic_fetch_xor:
7140b57cec5SDimitry Andric     Op = llvm::AtomicRMWInst::Xor;
7150b57cec5SDimitry Andric     break;
7160b57cec5SDimitry Andric 
7170b57cec5SDimitry Andric   case AtomicExpr::AO__atomic_nand_fetch:
7185f757f3fSDimitry Andric   case AtomicExpr::AO__scoped_atomic_nand_fetch:
7190b57cec5SDimitry Andric     PostOp = llvm::Instruction::And; // the NOT is special cased below
720bdd1243dSDimitry Andric     [[fallthrough]];
721349cc55cSDimitry Andric   case AtomicExpr::AO__c11_atomic_fetch_nand:
7220b57cec5SDimitry Andric   case AtomicExpr::AO__atomic_fetch_nand:
7235f757f3fSDimitry Andric   case AtomicExpr::AO__scoped_atomic_fetch_nand:
7240b57cec5SDimitry Andric     Op = llvm::AtomicRMWInst::Nand;
7250b57cec5SDimitry Andric     break;
7260b57cec5SDimitry Andric   }
7270b57cec5SDimitry Andric 
7280b57cec5SDimitry Andric   llvm::Value *LoadVal1 = CGF.Builder.CreateLoad(Val1);
7290b57cec5SDimitry Andric   llvm::AtomicRMWInst *RMWI =
7305f757f3fSDimitry Andric       CGF.Builder.CreateAtomicRMW(Op, Ptr, LoadVal1, Order, Scope);
7310b57cec5SDimitry Andric   RMWI->setVolatile(E->isVolatile());
7320b57cec5SDimitry Andric 
7330b57cec5SDimitry Andric   // For __atomic_*_fetch operations, perform the operation again to
7340b57cec5SDimitry Andric   // determine the value which was written.
7350b57cec5SDimitry Andric   llvm::Value *Result = RMWI;
736480093f4SDimitry Andric   if (PostOpMinMax)
737480093f4SDimitry Andric     Result = EmitPostAtomicMinMax(CGF.Builder, E->getOp(),
738480093f4SDimitry Andric                                   E->getValueType()->isSignedIntegerType(),
739480093f4SDimitry Andric                                   RMWI, LoadVal1);
740480093f4SDimitry Andric   else if (PostOp)
741480093f4SDimitry Andric     Result = CGF.Builder.CreateBinOp((llvm::Instruction::BinaryOps)PostOp, RMWI,
742480093f4SDimitry Andric                                      LoadVal1);
7435f757f3fSDimitry Andric   if (E->getOp() == AtomicExpr::AO__atomic_nand_fetch ||
7445f757f3fSDimitry Andric       E->getOp() == AtomicExpr::AO__scoped_atomic_nand_fetch)
7450b57cec5SDimitry Andric     Result = CGF.Builder.CreateNot(Result);
7460b57cec5SDimitry Andric   CGF.Builder.CreateStore(Result, Dest);
7470b57cec5SDimitry Andric }
7480b57cec5SDimitry Andric 
7490b57cec5SDimitry Andric // This function emits any expression (scalar, complex, or aggregate)
7500b57cec5SDimitry Andric // into a temporary alloca.
7510b57cec5SDimitry Andric static Address
7520b57cec5SDimitry Andric EmitValToTemp(CodeGenFunction &CGF, Expr *E) {
7530b57cec5SDimitry Andric   Address DeclPtr = CGF.CreateMemTemp(E->getType(), ".atomictmp");
7540b57cec5SDimitry Andric   CGF.EmitAnyExprToMem(E, DeclPtr, E->getType().getQualifiers(),
7550b57cec5SDimitry Andric                        /*Init*/ true);
7560b57cec5SDimitry Andric   return DeclPtr;
7570b57cec5SDimitry Andric }
7580b57cec5SDimitry Andric 
7590b57cec5SDimitry Andric static void EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *Expr, Address Dest,
7600b57cec5SDimitry Andric                          Address Ptr, Address Val1, Address Val2,
7610b57cec5SDimitry Andric                          llvm::Value *IsWeak, llvm::Value *FailureOrder,
7620b57cec5SDimitry Andric                          uint64_t Size, llvm::AtomicOrdering Order,
7630b57cec5SDimitry Andric                          llvm::Value *Scope) {
7640b57cec5SDimitry Andric   auto ScopeModel = Expr->getScopeModel();
7650b57cec5SDimitry Andric 
7660b57cec5SDimitry Andric   // LLVM atomic instructions always have synch scope. If clang atomic
7670b57cec5SDimitry Andric   // expression has no scope operand, use default LLVM synch scope.
7680b57cec5SDimitry Andric   if (!ScopeModel) {
7690b57cec5SDimitry Andric     EmitAtomicOp(CGF, Expr, Dest, Ptr, Val1, Val2, IsWeak, FailureOrder, Size,
7700b57cec5SDimitry Andric                  Order, CGF.CGM.getLLVMContext().getOrInsertSyncScopeID(""));
7710b57cec5SDimitry Andric     return;
7720b57cec5SDimitry Andric   }
7730b57cec5SDimitry Andric 
7740b57cec5SDimitry Andric   // Handle constant scope.
7750b57cec5SDimitry Andric   if (auto SC = dyn_cast<llvm::ConstantInt>(Scope)) {
7760b57cec5SDimitry Andric     auto SCID = CGF.getTargetHooks().getLLVMSyncScopeID(
7770b57cec5SDimitry Andric         CGF.CGM.getLangOpts(), ScopeModel->map(SC->getZExtValue()),
7780b57cec5SDimitry Andric         Order, CGF.CGM.getLLVMContext());
7790b57cec5SDimitry Andric     EmitAtomicOp(CGF, Expr, Dest, Ptr, Val1, Val2, IsWeak, FailureOrder, Size,
7800b57cec5SDimitry Andric                  Order, SCID);
7810b57cec5SDimitry Andric     return;
7820b57cec5SDimitry Andric   }
7830b57cec5SDimitry Andric 
7840b57cec5SDimitry Andric   // Handle non-constant scope.
7850b57cec5SDimitry Andric   auto &Builder = CGF.Builder;
7860b57cec5SDimitry Andric   auto Scopes = ScopeModel->getRuntimeValues();
7870b57cec5SDimitry Andric   llvm::DenseMap<unsigned, llvm::BasicBlock *> BB;
7880b57cec5SDimitry Andric   for (auto S : Scopes)
7890b57cec5SDimitry Andric     BB[S] = CGF.createBasicBlock(getAsString(ScopeModel->map(S)), CGF.CurFn);
7900b57cec5SDimitry Andric 
7910b57cec5SDimitry Andric   llvm::BasicBlock *ContBB =
7920b57cec5SDimitry Andric       CGF.createBasicBlock("atomic.scope.continue", CGF.CurFn);
7930b57cec5SDimitry Andric 
7940b57cec5SDimitry Andric   auto *SC = Builder.CreateIntCast(Scope, Builder.getInt32Ty(), false);
7950b57cec5SDimitry Andric   // If unsupported synch scope is encountered at run time, assume a fallback
7960b57cec5SDimitry Andric   // synch scope value.
7970b57cec5SDimitry Andric   auto FallBack = ScopeModel->getFallBackValue();
7980b57cec5SDimitry Andric   llvm::SwitchInst *SI = Builder.CreateSwitch(SC, BB[FallBack]);
7990b57cec5SDimitry Andric   for (auto S : Scopes) {
8000b57cec5SDimitry Andric     auto *B = BB[S];
8010b57cec5SDimitry Andric     if (S != FallBack)
8020b57cec5SDimitry Andric       SI->addCase(Builder.getInt32(S), B);
8030b57cec5SDimitry Andric 
8040b57cec5SDimitry Andric     Builder.SetInsertPoint(B);
8050b57cec5SDimitry Andric     EmitAtomicOp(CGF, Expr, Dest, Ptr, Val1, Val2, IsWeak, FailureOrder, Size,
8060b57cec5SDimitry Andric                  Order,
8070b57cec5SDimitry Andric                  CGF.getTargetHooks().getLLVMSyncScopeID(CGF.CGM.getLangOpts(),
8080b57cec5SDimitry Andric                                                          ScopeModel->map(S),
8090b57cec5SDimitry Andric                                                          Order,
8100b57cec5SDimitry Andric                                                          CGF.getLLVMContext()));
8110b57cec5SDimitry Andric     Builder.CreateBr(ContBB);
8120b57cec5SDimitry Andric   }
8130b57cec5SDimitry Andric 
8140b57cec5SDimitry Andric   Builder.SetInsertPoint(ContBB);
8150b57cec5SDimitry Andric }
8160b57cec5SDimitry Andric 
8170b57cec5SDimitry Andric RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) {
8180b57cec5SDimitry Andric   QualType AtomicTy = E->getPtr()->getType()->getPointeeType();
8190b57cec5SDimitry Andric   QualType MemTy = AtomicTy;
8200b57cec5SDimitry Andric   if (const AtomicType *AT = AtomicTy->getAs<AtomicType>())
8210b57cec5SDimitry Andric     MemTy = AT->getValueType();
8220b57cec5SDimitry Andric   llvm::Value *IsWeak = nullptr, *OrderFail = nullptr;
8230b57cec5SDimitry Andric 
8240b57cec5SDimitry Andric   Address Val1 = Address::invalid();
8250b57cec5SDimitry Andric   Address Val2 = Address::invalid();
8260b57cec5SDimitry Andric   Address Dest = Address::invalid();
8270b57cec5SDimitry Andric   Address Ptr = EmitPointerWithAlignment(E->getPtr());
8280b57cec5SDimitry Andric 
8290b57cec5SDimitry Andric   if (E->getOp() == AtomicExpr::AO__c11_atomic_init ||
8300b57cec5SDimitry Andric       E->getOp() == AtomicExpr::AO__opencl_atomic_init) {
8310b57cec5SDimitry Andric     LValue lvalue = MakeAddrLValue(Ptr, AtomicTy);
8320b57cec5SDimitry Andric     EmitAtomicInit(E->getVal1(), lvalue);
8330b57cec5SDimitry Andric     return RValue::get(nullptr);
8340b57cec5SDimitry Andric   }
8350b57cec5SDimitry Andric 
836e8d8bef9SDimitry Andric   auto TInfo = getContext().getTypeInfoInChars(AtomicTy);
837e8d8bef9SDimitry Andric   uint64_t Size = TInfo.Width.getQuantity();
8380b57cec5SDimitry Andric   unsigned MaxInlineWidthInBits = getTarget().getMaxAtomicInlineWidth();
8390b57cec5SDimitry Andric 
840e8d8bef9SDimitry Andric   CharUnits MaxInlineWidth =
841e8d8bef9SDimitry Andric       getContext().toCharUnitsFromBits(MaxInlineWidthInBits);
842e8d8bef9SDimitry Andric   DiagnosticsEngine &Diags = CGM.getDiags();
843*0fca6ea1SDimitry Andric   bool Misaligned = (Ptr.getAlignment() % TInfo.Width) != 0;
844*0fca6ea1SDimitry Andric   bool Oversized = getContext().toBits(TInfo.Width) > MaxInlineWidthInBits;
845e8d8bef9SDimitry Andric   if (Misaligned) {
846e8d8bef9SDimitry Andric     Diags.Report(E->getBeginLoc(), diag::warn_atomic_op_misaligned)
847e8d8bef9SDimitry Andric         << (int)TInfo.Width.getQuantity()
848e8d8bef9SDimitry Andric         << (int)Ptr.getAlignment().getQuantity();
849e8d8bef9SDimitry Andric   }
850e8d8bef9SDimitry Andric   if (Oversized) {
851e8d8bef9SDimitry Andric     Diags.Report(E->getBeginLoc(), diag::warn_atomic_op_oversized)
852e8d8bef9SDimitry Andric         << (int)TInfo.Width.getQuantity() << (int)MaxInlineWidth.getQuantity();
8530b57cec5SDimitry Andric   }
8540b57cec5SDimitry Andric 
8550b57cec5SDimitry Andric   llvm::Value *Order = EmitScalarExpr(E->getOrder());
8560b57cec5SDimitry Andric   llvm::Value *Scope =
8570b57cec5SDimitry Andric       E->getScopeModel() ? EmitScalarExpr(E->getScope()) : nullptr;
858*0fca6ea1SDimitry Andric   bool ShouldCastToIntPtrTy = true;
8590b57cec5SDimitry Andric 
8600b57cec5SDimitry Andric   switch (E->getOp()) {
8610b57cec5SDimitry Andric   case AtomicExpr::AO__c11_atomic_init:
8620b57cec5SDimitry Andric   case AtomicExpr::AO__opencl_atomic_init:
8630b57cec5SDimitry Andric     llvm_unreachable("Already handled above with EmitAtomicInit!");
8640b57cec5SDimitry Andric 
8655f757f3fSDimitry Andric   case AtomicExpr::AO__atomic_load_n:
8665f757f3fSDimitry Andric   case AtomicExpr::AO__scoped_atomic_load_n:
8670b57cec5SDimitry Andric   case AtomicExpr::AO__c11_atomic_load:
8680b57cec5SDimitry Andric   case AtomicExpr::AO__opencl_atomic_load:
8694824e7fdSDimitry Andric   case AtomicExpr::AO__hip_atomic_load:
8700b57cec5SDimitry Andric     break;
8710b57cec5SDimitry Andric 
8720b57cec5SDimitry Andric   case AtomicExpr::AO__atomic_load:
8735f757f3fSDimitry Andric   case AtomicExpr::AO__scoped_atomic_load:
8740b57cec5SDimitry Andric     Dest = EmitPointerWithAlignment(E->getVal1());
8750b57cec5SDimitry Andric     break;
8760b57cec5SDimitry Andric 
8770b57cec5SDimitry Andric   case AtomicExpr::AO__atomic_store:
8785f757f3fSDimitry Andric   case AtomicExpr::AO__scoped_atomic_store:
8790b57cec5SDimitry Andric     Val1 = EmitPointerWithAlignment(E->getVal1());
8800b57cec5SDimitry Andric     break;
8810b57cec5SDimitry Andric 
8820b57cec5SDimitry Andric   case AtomicExpr::AO__atomic_exchange:
8835f757f3fSDimitry Andric   case AtomicExpr::AO__scoped_atomic_exchange:
8840b57cec5SDimitry Andric     Val1 = EmitPointerWithAlignment(E->getVal1());
8850b57cec5SDimitry Andric     Dest = EmitPointerWithAlignment(E->getVal2());
8860b57cec5SDimitry Andric     break;
8870b57cec5SDimitry Andric 
8885f757f3fSDimitry Andric   case AtomicExpr::AO__atomic_compare_exchange:
8895f757f3fSDimitry Andric   case AtomicExpr::AO__atomic_compare_exchange_n:
8900b57cec5SDimitry Andric   case AtomicExpr::AO__c11_atomic_compare_exchange_weak:
8915f757f3fSDimitry Andric   case AtomicExpr::AO__c11_atomic_compare_exchange_strong:
8925f757f3fSDimitry Andric   case AtomicExpr::AO__hip_atomic_compare_exchange_weak:
8934824e7fdSDimitry Andric   case AtomicExpr::AO__hip_atomic_compare_exchange_strong:
8940b57cec5SDimitry Andric   case AtomicExpr::AO__opencl_atomic_compare_exchange_weak:
8955f757f3fSDimitry Andric   case AtomicExpr::AO__opencl_atomic_compare_exchange_strong:
8965f757f3fSDimitry Andric   case AtomicExpr::AO__scoped_atomic_compare_exchange:
8975f757f3fSDimitry Andric   case AtomicExpr::AO__scoped_atomic_compare_exchange_n:
8980b57cec5SDimitry Andric     Val1 = EmitPointerWithAlignment(E->getVal1());
8995f757f3fSDimitry Andric     if (E->getOp() == AtomicExpr::AO__atomic_compare_exchange ||
9005f757f3fSDimitry Andric         E->getOp() == AtomicExpr::AO__scoped_atomic_compare_exchange)
9010b57cec5SDimitry Andric       Val2 = EmitPointerWithAlignment(E->getVal2());
9020b57cec5SDimitry Andric     else
9030b57cec5SDimitry Andric       Val2 = EmitValToTemp(*this, E->getVal2());
9040b57cec5SDimitry Andric     OrderFail = EmitScalarExpr(E->getOrderFail());
9050b57cec5SDimitry Andric     if (E->getOp() == AtomicExpr::AO__atomic_compare_exchange_n ||
9065f757f3fSDimitry Andric         E->getOp() == AtomicExpr::AO__atomic_compare_exchange ||
9075f757f3fSDimitry Andric         E->getOp() == AtomicExpr::AO__scoped_atomic_compare_exchange_n ||
9085f757f3fSDimitry Andric         E->getOp() == AtomicExpr::AO__scoped_atomic_compare_exchange)
9090b57cec5SDimitry Andric       IsWeak = EmitScalarExpr(E->getWeak());
9100b57cec5SDimitry Andric     break;
9110b57cec5SDimitry Andric 
9120b57cec5SDimitry Andric   case AtomicExpr::AO__c11_atomic_fetch_add:
9130b57cec5SDimitry Andric   case AtomicExpr::AO__c11_atomic_fetch_sub:
9144824e7fdSDimitry Andric   case AtomicExpr::AO__hip_atomic_fetch_add:
91506c3fb27SDimitry Andric   case AtomicExpr::AO__hip_atomic_fetch_sub:
9160b57cec5SDimitry Andric   case AtomicExpr::AO__opencl_atomic_fetch_add:
9170b57cec5SDimitry Andric   case AtomicExpr::AO__opencl_atomic_fetch_sub:
9180b57cec5SDimitry Andric     if (MemTy->isPointerType()) {
9190b57cec5SDimitry Andric       // For pointer arithmetic, we're required to do a bit of math:
9200b57cec5SDimitry Andric       // adding 1 to an int* is not the same as adding 1 to a uintptr_t.
9210b57cec5SDimitry Andric       // ... but only for the C11 builtins. The GNU builtins expect the
9220b57cec5SDimitry Andric       // user to multiply by sizeof(T).
9230b57cec5SDimitry Andric       QualType Val1Ty = E->getVal1()->getType();
9240b57cec5SDimitry Andric       llvm::Value *Val1Scalar = EmitScalarExpr(E->getVal1());
9250b57cec5SDimitry Andric       CharUnits PointeeIncAmt =
9260b57cec5SDimitry Andric           getContext().getTypeSizeInChars(MemTy->getPointeeType());
9270b57cec5SDimitry Andric       Val1Scalar = Builder.CreateMul(Val1Scalar, CGM.getSize(PointeeIncAmt));
9280b57cec5SDimitry Andric       auto Temp = CreateMemTemp(Val1Ty, ".atomictmp");
9290b57cec5SDimitry Andric       Val1 = Temp;
9300b57cec5SDimitry Andric       EmitStoreOfScalar(Val1Scalar, MakeAddrLValue(Temp, Val1Ty));
9310b57cec5SDimitry Andric       break;
9320b57cec5SDimitry Andric     }
933bdd1243dSDimitry Andric     [[fallthrough]];
9340b57cec5SDimitry Andric   case AtomicExpr::AO__atomic_fetch_add:
93506c3fb27SDimitry Andric   case AtomicExpr::AO__atomic_fetch_max:
93606c3fb27SDimitry Andric   case AtomicExpr::AO__atomic_fetch_min:
9370b57cec5SDimitry Andric   case AtomicExpr::AO__atomic_fetch_sub:
9380b57cec5SDimitry Andric   case AtomicExpr::AO__atomic_add_fetch:
93906c3fb27SDimitry Andric   case AtomicExpr::AO__atomic_max_fetch:
94006c3fb27SDimitry Andric   case AtomicExpr::AO__atomic_min_fetch:
9410b57cec5SDimitry Andric   case AtomicExpr::AO__atomic_sub_fetch:
94206c3fb27SDimitry Andric   case AtomicExpr::AO__c11_atomic_fetch_max:
94306c3fb27SDimitry Andric   case AtomicExpr::AO__c11_atomic_fetch_min:
94406c3fb27SDimitry Andric   case AtomicExpr::AO__opencl_atomic_fetch_max:
94506c3fb27SDimitry Andric   case AtomicExpr::AO__opencl_atomic_fetch_min:
94606c3fb27SDimitry Andric   case AtomicExpr::AO__hip_atomic_fetch_max:
94706c3fb27SDimitry Andric   case AtomicExpr::AO__hip_atomic_fetch_min:
9485f757f3fSDimitry Andric   case AtomicExpr::AO__scoped_atomic_fetch_add:
9495f757f3fSDimitry Andric   case AtomicExpr::AO__scoped_atomic_fetch_max:
9505f757f3fSDimitry Andric   case AtomicExpr::AO__scoped_atomic_fetch_min:
9515f757f3fSDimitry Andric   case AtomicExpr::AO__scoped_atomic_fetch_sub:
9525f757f3fSDimitry Andric   case AtomicExpr::AO__scoped_atomic_add_fetch:
9535f757f3fSDimitry Andric   case AtomicExpr::AO__scoped_atomic_max_fetch:
9545f757f3fSDimitry Andric   case AtomicExpr::AO__scoped_atomic_min_fetch:
9555f757f3fSDimitry Andric   case AtomicExpr::AO__scoped_atomic_sub_fetch:
956fe6060f1SDimitry Andric     ShouldCastToIntPtrTy = !MemTy->isFloatingType();
957bdd1243dSDimitry Andric     [[fallthrough]];
958fe6060f1SDimitry Andric 
9595f757f3fSDimitry Andric   case AtomicExpr::AO__atomic_fetch_and:
9605f757f3fSDimitry Andric   case AtomicExpr::AO__atomic_fetch_nand:
9615f757f3fSDimitry Andric   case AtomicExpr::AO__atomic_fetch_or:
9625f757f3fSDimitry Andric   case AtomicExpr::AO__atomic_fetch_xor:
9635f757f3fSDimitry Andric   case AtomicExpr::AO__atomic_and_fetch:
9645f757f3fSDimitry Andric   case AtomicExpr::AO__atomic_nand_fetch:
9655f757f3fSDimitry Andric   case AtomicExpr::AO__atomic_or_fetch:
9665f757f3fSDimitry Andric   case AtomicExpr::AO__atomic_xor_fetch:
9670b57cec5SDimitry Andric   case AtomicExpr::AO__atomic_store_n:
9680b57cec5SDimitry Andric   case AtomicExpr::AO__atomic_exchange_n:
9690b57cec5SDimitry Andric   case AtomicExpr::AO__c11_atomic_fetch_and:
9705f757f3fSDimitry Andric   case AtomicExpr::AO__c11_atomic_fetch_nand:
9710b57cec5SDimitry Andric   case AtomicExpr::AO__c11_atomic_fetch_or:
9720b57cec5SDimitry Andric   case AtomicExpr::AO__c11_atomic_fetch_xor:
9735f757f3fSDimitry Andric   case AtomicExpr::AO__c11_atomic_store:
9745f757f3fSDimitry Andric   case AtomicExpr::AO__c11_atomic_exchange:
9755f757f3fSDimitry Andric   case AtomicExpr::AO__hip_atomic_fetch_and:
9765f757f3fSDimitry Andric   case AtomicExpr::AO__hip_atomic_fetch_or:
9775f757f3fSDimitry Andric   case AtomicExpr::AO__hip_atomic_fetch_xor:
9785f757f3fSDimitry Andric   case AtomicExpr::AO__hip_atomic_store:
9795f757f3fSDimitry Andric   case AtomicExpr::AO__hip_atomic_exchange:
9800b57cec5SDimitry Andric   case AtomicExpr::AO__opencl_atomic_fetch_and:
9810b57cec5SDimitry Andric   case AtomicExpr::AO__opencl_atomic_fetch_or:
9820b57cec5SDimitry Andric   case AtomicExpr::AO__opencl_atomic_fetch_xor:
9835f757f3fSDimitry Andric   case AtomicExpr::AO__opencl_atomic_store:
9845f757f3fSDimitry Andric   case AtomicExpr::AO__opencl_atomic_exchange:
9855f757f3fSDimitry Andric   case AtomicExpr::AO__scoped_atomic_fetch_and:
9865f757f3fSDimitry Andric   case AtomicExpr::AO__scoped_atomic_fetch_nand:
9875f757f3fSDimitry Andric   case AtomicExpr::AO__scoped_atomic_fetch_or:
9885f757f3fSDimitry Andric   case AtomicExpr::AO__scoped_atomic_fetch_xor:
9895f757f3fSDimitry Andric   case AtomicExpr::AO__scoped_atomic_and_fetch:
9905f757f3fSDimitry Andric   case AtomicExpr::AO__scoped_atomic_nand_fetch:
9915f757f3fSDimitry Andric   case AtomicExpr::AO__scoped_atomic_or_fetch:
9925f757f3fSDimitry Andric   case AtomicExpr::AO__scoped_atomic_xor_fetch:
9935f757f3fSDimitry Andric   case AtomicExpr::AO__scoped_atomic_store_n:
9945f757f3fSDimitry Andric   case AtomicExpr::AO__scoped_atomic_exchange_n:
9950b57cec5SDimitry Andric     Val1 = EmitValToTemp(*this, E->getVal1());
9960b57cec5SDimitry Andric     break;
9970b57cec5SDimitry Andric   }
9980b57cec5SDimitry Andric 
9990b57cec5SDimitry Andric   QualType RValTy = E->getType().getUnqualifiedType();
10000b57cec5SDimitry Andric 
10010b57cec5SDimitry Andric   // The inlined atomics only function on iN types, where N is a power of 2. We
10020b57cec5SDimitry Andric   // need to make sure (via temporaries if necessary) that all incoming values
10030b57cec5SDimitry Andric   // are compatible.
10040b57cec5SDimitry Andric   LValue AtomicVal = MakeAddrLValue(Ptr, AtomicTy);
10050b57cec5SDimitry Andric   AtomicInfo Atomics(*this, AtomicVal);
10060b57cec5SDimitry Andric 
1007fe6060f1SDimitry Andric   if (ShouldCastToIntPtrTy) {
100806c3fb27SDimitry Andric     Ptr = Atomics.castToAtomicIntPointer(Ptr);
1009fe6060f1SDimitry Andric     if (Val1.isValid())
1010fe6060f1SDimitry Andric       Val1 = Atomics.convertToAtomicIntPointer(Val1);
1011fe6060f1SDimitry Andric     if (Val2.isValid())
1012fe6060f1SDimitry Andric       Val2 = Atomics.convertToAtomicIntPointer(Val2);
1013fe6060f1SDimitry Andric   }
1014fe6060f1SDimitry Andric   if (Dest.isValid()) {
1015fe6060f1SDimitry Andric     if (ShouldCastToIntPtrTy)
101606c3fb27SDimitry Andric       Dest = Atomics.castToAtomicIntPointer(Dest);
1017fe6060f1SDimitry Andric   } else if (E->isCmpXChg())
10180b57cec5SDimitry Andric     Dest = CreateMemTemp(RValTy, "cmpxchg.bool");
1019fe6060f1SDimitry Andric   else if (!RValTy->isVoidType()) {
1020fe6060f1SDimitry Andric     Dest = Atomics.CreateTempAlloca();
1021fe6060f1SDimitry Andric     if (ShouldCastToIntPtrTy)
102206c3fb27SDimitry Andric       Dest = Atomics.castToAtomicIntPointer(Dest);
1023fe6060f1SDimitry Andric   }
10240b57cec5SDimitry Andric 
1025*0fca6ea1SDimitry Andric   bool PowerOf2Size = (Size & (Size - 1)) == 0;
1026*0fca6ea1SDimitry Andric   bool UseLibcall = !PowerOf2Size || (Size > 16);
1027*0fca6ea1SDimitry Andric 
1028*0fca6ea1SDimitry Andric   // For atomics larger than 16 bytes, emit a libcall from the frontend. This
1029*0fca6ea1SDimitry Andric   // avoids the overhead of dealing with excessively-large value types in IR.
1030*0fca6ea1SDimitry Andric   // Non-power-of-2 values also lower to libcall here, as they are not currently
1031*0fca6ea1SDimitry Andric   // permitted in IR instructions (although that constraint could be relaxed in
1032*0fca6ea1SDimitry Andric   // the future). For other cases where a libcall is required on a given
1033*0fca6ea1SDimitry Andric   // platform, we let the backend handle it (this includes handling for all of
1034*0fca6ea1SDimitry Andric   // the size-optimized libcall variants, which are only valid up to 16 bytes.)
1035*0fca6ea1SDimitry Andric   //
1036*0fca6ea1SDimitry Andric   // See: https://llvm.org/docs/Atomics.html#libcalls-atomic
10370b57cec5SDimitry Andric   if (UseLibcall) {
10380b57cec5SDimitry Andric     CallArgList Args;
1039*0fca6ea1SDimitry Andric     // For non-optimized library calls, the size is the first parameter.
10400b57cec5SDimitry Andric     Args.add(RValue::get(llvm::ConstantInt::get(SizeTy, Size)),
10410b57cec5SDimitry Andric              getContext().getSizeType());
1042*0fca6ea1SDimitry Andric 
1043*0fca6ea1SDimitry Andric     // The atomic address is the second parameter.
10440b57cec5SDimitry Andric     // The OpenCL atomic library functions only accept pointer arguments to
10450b57cec5SDimitry Andric     // generic address space.
10460b57cec5SDimitry Andric     auto CastToGenericAddrSpace = [&](llvm::Value *V, QualType PT) {
10470b57cec5SDimitry Andric       if (!E->isOpenCL())
10480b57cec5SDimitry Andric         return V;
1049a7dea167SDimitry Andric       auto AS = PT->castAs<PointerType>()->getPointeeType().getAddressSpace();
10500b57cec5SDimitry Andric       if (AS == LangAS::opencl_generic)
10510b57cec5SDimitry Andric         return V;
10520b57cec5SDimitry Andric       auto DestAS = getContext().getTargetAddressSpace(LangAS::opencl_generic);
105306c3fb27SDimitry Andric       auto *DestType = llvm::PointerType::get(getLLVMContext(), DestAS);
10540b57cec5SDimitry Andric 
10550b57cec5SDimitry Andric       return getTargetHooks().performAddrSpaceCast(
10560b57cec5SDimitry Andric           *this, V, AS, LangAS::opencl_generic, DestType, false);
10570b57cec5SDimitry Andric     };
10580b57cec5SDimitry Andric 
1059*0fca6ea1SDimitry Andric     Args.add(RValue::get(CastToGenericAddrSpace(Ptr.emitRawPointer(*this),
106006c3fb27SDimitry Andric                                                 E->getPtr()->getType())),
10610b57cec5SDimitry Andric              getContext().VoidPtrTy);
10620b57cec5SDimitry Andric 
1063*0fca6ea1SDimitry Andric     // The next 1-3 parameters are op-dependent.
10640b57cec5SDimitry Andric     std::string LibCallName;
10650b57cec5SDimitry Andric     QualType RetTy;
10660b57cec5SDimitry Andric     bool HaveRetTy = false;
10670b57cec5SDimitry Andric     switch (E->getOp()) {
10680b57cec5SDimitry Andric     case AtomicExpr::AO__c11_atomic_init:
10690b57cec5SDimitry Andric     case AtomicExpr::AO__opencl_atomic_init:
10700b57cec5SDimitry Andric       llvm_unreachable("Already handled!");
10710b57cec5SDimitry Andric 
10720b57cec5SDimitry Andric     // There is only one libcall for compare an exchange, because there is no
10730b57cec5SDimitry Andric     // optimisation benefit possible from a libcall version of a weak compare
10740b57cec5SDimitry Andric     // and exchange.
10750b57cec5SDimitry Andric     // bool __atomic_compare_exchange(size_t size, void *mem, void *expected,
10760b57cec5SDimitry Andric     //                                void *desired, int success, int failure)
10770b57cec5SDimitry Andric     case AtomicExpr::AO__atomic_compare_exchange:
10780b57cec5SDimitry Andric     case AtomicExpr::AO__atomic_compare_exchange_n:
10795f757f3fSDimitry Andric     case AtomicExpr::AO__c11_atomic_compare_exchange_weak:
10805f757f3fSDimitry Andric     case AtomicExpr::AO__c11_atomic_compare_exchange_strong:
10815f757f3fSDimitry Andric     case AtomicExpr::AO__hip_atomic_compare_exchange_weak:
10825f757f3fSDimitry Andric     case AtomicExpr::AO__hip_atomic_compare_exchange_strong:
10835f757f3fSDimitry Andric     case AtomicExpr::AO__opencl_atomic_compare_exchange_weak:
10845f757f3fSDimitry Andric     case AtomicExpr::AO__opencl_atomic_compare_exchange_strong:
10855f757f3fSDimitry Andric     case AtomicExpr::AO__scoped_atomic_compare_exchange:
10865f757f3fSDimitry Andric     case AtomicExpr::AO__scoped_atomic_compare_exchange_n:
10870b57cec5SDimitry Andric       LibCallName = "__atomic_compare_exchange";
10880b57cec5SDimitry Andric       RetTy = getContext().BoolTy;
10890b57cec5SDimitry Andric       HaveRetTy = true;
1090*0fca6ea1SDimitry Andric       Args.add(RValue::get(CastToGenericAddrSpace(Val1.emitRawPointer(*this),
109106c3fb27SDimitry Andric                                                   E->getVal1()->getType())),
10920b57cec5SDimitry Andric                getContext().VoidPtrTy);
1093*0fca6ea1SDimitry Andric       Args.add(RValue::get(CastToGenericAddrSpace(Val2.emitRawPointer(*this),
1094*0fca6ea1SDimitry Andric                                                   E->getVal2()->getType())),
1095*0fca6ea1SDimitry Andric                getContext().VoidPtrTy);
10960b57cec5SDimitry Andric       Args.add(RValue::get(Order), getContext().IntTy);
10970b57cec5SDimitry Andric       Order = OrderFail;
10980b57cec5SDimitry Andric       break;
10990b57cec5SDimitry Andric     // void __atomic_exchange(size_t size, void *mem, void *val, void *return,
11000b57cec5SDimitry Andric     //                        int order)
11010b57cec5SDimitry Andric     case AtomicExpr::AO__atomic_exchange:
11025f757f3fSDimitry Andric     case AtomicExpr::AO__atomic_exchange_n:
11035f757f3fSDimitry Andric     case AtomicExpr::AO__c11_atomic_exchange:
11044824e7fdSDimitry Andric     case AtomicExpr::AO__hip_atomic_exchange:
11055f757f3fSDimitry Andric     case AtomicExpr::AO__opencl_atomic_exchange:
11065f757f3fSDimitry Andric     case AtomicExpr::AO__scoped_atomic_exchange:
11075f757f3fSDimitry Andric     case AtomicExpr::AO__scoped_atomic_exchange_n:
11080b57cec5SDimitry Andric       LibCallName = "__atomic_exchange";
1109*0fca6ea1SDimitry Andric       Args.add(RValue::get(CastToGenericAddrSpace(Val1.emitRawPointer(*this),
1110*0fca6ea1SDimitry Andric                                                   E->getVal1()->getType())),
1111*0fca6ea1SDimitry Andric                getContext().VoidPtrTy);
11120b57cec5SDimitry Andric       break;
11130b57cec5SDimitry Andric     // void __atomic_store(size_t size, void *mem, void *val, int order)
11140b57cec5SDimitry Andric     case AtomicExpr::AO__atomic_store:
11150b57cec5SDimitry Andric     case AtomicExpr::AO__atomic_store_n:
11165f757f3fSDimitry Andric     case AtomicExpr::AO__c11_atomic_store:
11175f757f3fSDimitry Andric     case AtomicExpr::AO__hip_atomic_store:
11185f757f3fSDimitry Andric     case AtomicExpr::AO__opencl_atomic_store:
11195f757f3fSDimitry Andric     case AtomicExpr::AO__scoped_atomic_store:
11205f757f3fSDimitry Andric     case AtomicExpr::AO__scoped_atomic_store_n:
11210b57cec5SDimitry Andric       LibCallName = "__atomic_store";
11220b57cec5SDimitry Andric       RetTy = getContext().VoidTy;
11230b57cec5SDimitry Andric       HaveRetTy = true;
1124*0fca6ea1SDimitry Andric       Args.add(RValue::get(CastToGenericAddrSpace(Val1.emitRawPointer(*this),
1125*0fca6ea1SDimitry Andric                                                   E->getVal1()->getType())),
1126*0fca6ea1SDimitry Andric                getContext().VoidPtrTy);
11270b57cec5SDimitry Andric       break;
11280b57cec5SDimitry Andric     // void __atomic_load(size_t size, void *mem, void *return, int order)
11290b57cec5SDimitry Andric     case AtomicExpr::AO__atomic_load:
11300b57cec5SDimitry Andric     case AtomicExpr::AO__atomic_load_n:
11315f757f3fSDimitry Andric     case AtomicExpr::AO__c11_atomic_load:
11325f757f3fSDimitry Andric     case AtomicExpr::AO__hip_atomic_load:
11335f757f3fSDimitry Andric     case AtomicExpr::AO__opencl_atomic_load:
11345f757f3fSDimitry Andric     case AtomicExpr::AO__scoped_atomic_load:
11355f757f3fSDimitry Andric     case AtomicExpr::AO__scoped_atomic_load_n:
11360b57cec5SDimitry Andric       LibCallName = "__atomic_load";
11370b57cec5SDimitry Andric       break;
11380b57cec5SDimitry Andric     case AtomicExpr::AO__atomic_add_fetch:
11395f757f3fSDimitry Andric     case AtomicExpr::AO__scoped_atomic_add_fetch:
11400b57cec5SDimitry Andric     case AtomicExpr::AO__atomic_fetch_add:
11415f757f3fSDimitry Andric     case AtomicExpr::AO__c11_atomic_fetch_add:
11424824e7fdSDimitry Andric     case AtomicExpr::AO__hip_atomic_fetch_add:
11435f757f3fSDimitry Andric     case AtomicExpr::AO__opencl_atomic_fetch_add:
11445f757f3fSDimitry Andric     case AtomicExpr::AO__scoped_atomic_fetch_add:
11450b57cec5SDimitry Andric     case AtomicExpr::AO__atomic_and_fetch:
11465f757f3fSDimitry Andric     case AtomicExpr::AO__scoped_atomic_and_fetch:
11470b57cec5SDimitry Andric     case AtomicExpr::AO__atomic_fetch_and:
11485f757f3fSDimitry Andric     case AtomicExpr::AO__c11_atomic_fetch_and:
11495f757f3fSDimitry Andric     case AtomicExpr::AO__hip_atomic_fetch_and:
11505f757f3fSDimitry Andric     case AtomicExpr::AO__opencl_atomic_fetch_and:
11515f757f3fSDimitry Andric     case AtomicExpr::AO__scoped_atomic_fetch_and:
11520b57cec5SDimitry Andric     case AtomicExpr::AO__atomic_or_fetch:
11535f757f3fSDimitry Andric     case AtomicExpr::AO__scoped_atomic_or_fetch:
11540b57cec5SDimitry Andric     case AtomicExpr::AO__atomic_fetch_or:
11555f757f3fSDimitry Andric     case AtomicExpr::AO__c11_atomic_fetch_or:
11565f757f3fSDimitry Andric     case AtomicExpr::AO__hip_atomic_fetch_or:
11575f757f3fSDimitry Andric     case AtomicExpr::AO__opencl_atomic_fetch_or:
11585f757f3fSDimitry Andric     case AtomicExpr::AO__scoped_atomic_fetch_or:
11590b57cec5SDimitry Andric     case AtomicExpr::AO__atomic_sub_fetch:
11605f757f3fSDimitry Andric     case AtomicExpr::AO__scoped_atomic_sub_fetch:
11610b57cec5SDimitry Andric     case AtomicExpr::AO__atomic_fetch_sub:
11625f757f3fSDimitry Andric     case AtomicExpr::AO__c11_atomic_fetch_sub:
11635f757f3fSDimitry Andric     case AtomicExpr::AO__hip_atomic_fetch_sub:
11645f757f3fSDimitry Andric     case AtomicExpr::AO__opencl_atomic_fetch_sub:
11655f757f3fSDimitry Andric     case AtomicExpr::AO__scoped_atomic_fetch_sub:
11660b57cec5SDimitry Andric     case AtomicExpr::AO__atomic_xor_fetch:
11675f757f3fSDimitry Andric     case AtomicExpr::AO__scoped_atomic_xor_fetch:
11680b57cec5SDimitry Andric     case AtomicExpr::AO__atomic_fetch_xor:
11695f757f3fSDimitry Andric     case AtomicExpr::AO__c11_atomic_fetch_xor:
11705f757f3fSDimitry Andric     case AtomicExpr::AO__hip_atomic_fetch_xor:
11715f757f3fSDimitry Andric     case AtomicExpr::AO__opencl_atomic_fetch_xor:
11725f757f3fSDimitry Andric     case AtomicExpr::AO__scoped_atomic_fetch_xor:
1173*0fca6ea1SDimitry Andric     case AtomicExpr::AO__atomic_nand_fetch:
1174*0fca6ea1SDimitry Andric     case AtomicExpr::AO__atomic_fetch_nand:
1175*0fca6ea1SDimitry Andric     case AtomicExpr::AO__c11_atomic_fetch_nand:
1176*0fca6ea1SDimitry Andric     case AtomicExpr::AO__scoped_atomic_fetch_nand:
1177*0fca6ea1SDimitry Andric     case AtomicExpr::AO__scoped_atomic_nand_fetch:
1178480093f4SDimitry Andric     case AtomicExpr::AO__atomic_min_fetch:
11790b57cec5SDimitry Andric     case AtomicExpr::AO__atomic_fetch_min:
11805f757f3fSDimitry Andric     case AtomicExpr::AO__c11_atomic_fetch_min:
11814824e7fdSDimitry Andric     case AtomicExpr::AO__hip_atomic_fetch_min:
11820b57cec5SDimitry Andric     case AtomicExpr::AO__opencl_atomic_fetch_min:
1183*0fca6ea1SDimitry Andric     case AtomicExpr::AO__scoped_atomic_fetch_min:
1184*0fca6ea1SDimitry Andric     case AtomicExpr::AO__scoped_atomic_min_fetch:
1185480093f4SDimitry Andric     case AtomicExpr::AO__atomic_max_fetch:
11860b57cec5SDimitry Andric     case AtomicExpr::AO__atomic_fetch_max:
11875f757f3fSDimitry Andric     case AtomicExpr::AO__c11_atomic_fetch_max:
11884824e7fdSDimitry Andric     case AtomicExpr::AO__hip_atomic_fetch_max:
11890b57cec5SDimitry Andric     case AtomicExpr::AO__opencl_atomic_fetch_max:
11905f757f3fSDimitry Andric     case AtomicExpr::AO__scoped_atomic_fetch_max:
1191*0fca6ea1SDimitry Andric     case AtomicExpr::AO__scoped_atomic_max_fetch:
1192*0fca6ea1SDimitry Andric       llvm_unreachable("Integral atomic operations always become atomicrmw!");
11930b57cec5SDimitry Andric     }
11940b57cec5SDimitry Andric 
11950b57cec5SDimitry Andric     if (E->isOpenCL()) {
1196*0fca6ea1SDimitry Andric       LibCallName =
1197*0fca6ea1SDimitry Andric           std::string("__opencl") + StringRef(LibCallName).drop_front(1).str();
11980b57cec5SDimitry Andric     }
11990b57cec5SDimitry Andric     // By default, assume we return a value of the atomic type.
12000b57cec5SDimitry Andric     if (!HaveRetTy) {
12010b57cec5SDimitry Andric       // Value is returned through parameter before the order.
12020b57cec5SDimitry Andric       RetTy = getContext().VoidTy;
1203*0fca6ea1SDimitry Andric       Args.add(RValue::get(
1204*0fca6ea1SDimitry Andric                    CastToGenericAddrSpace(Dest.emitRawPointer(*this), RetTy)),
1205*0fca6ea1SDimitry Andric                getContext().VoidPtrTy);
12060b57cec5SDimitry Andric     }
1207*0fca6ea1SDimitry Andric     // Order is always the last parameter.
12080b57cec5SDimitry Andric     Args.add(RValue::get(Order),
12090b57cec5SDimitry Andric              getContext().IntTy);
12100b57cec5SDimitry Andric     if (E->isOpenCL())
12110b57cec5SDimitry Andric       Args.add(RValue::get(Scope), getContext().IntTy);
12120b57cec5SDimitry Andric 
12130b57cec5SDimitry Andric     RValue Res = emitAtomicLibcall(*this, LibCallName, RetTy, Args);
12140b57cec5SDimitry Andric     // The value is returned directly from the libcall.
12150b57cec5SDimitry Andric     if (E->isCmpXChg())
12160b57cec5SDimitry Andric       return Res;
12170b57cec5SDimitry Andric 
12180b57cec5SDimitry Andric     if (RValTy->isVoidType())
12190b57cec5SDimitry Andric       return RValue::get(nullptr);
12200b57cec5SDimitry Andric 
122106c3fb27SDimitry Andric     return convertTempToRValue(Dest.withElementType(ConvertTypeForMem(RValTy)),
12220b57cec5SDimitry Andric                                RValTy, E->getExprLoc());
12230b57cec5SDimitry Andric   }
12240b57cec5SDimitry Andric 
12250b57cec5SDimitry Andric   bool IsStore = E->getOp() == AtomicExpr::AO__c11_atomic_store ||
12260b57cec5SDimitry Andric                  E->getOp() == AtomicExpr::AO__opencl_atomic_store ||
12274824e7fdSDimitry Andric                  E->getOp() == AtomicExpr::AO__hip_atomic_store ||
12280b57cec5SDimitry Andric                  E->getOp() == AtomicExpr::AO__atomic_store ||
12295f757f3fSDimitry Andric                  E->getOp() == AtomicExpr::AO__atomic_store_n ||
12305f757f3fSDimitry Andric                  E->getOp() == AtomicExpr::AO__scoped_atomic_store ||
12315f757f3fSDimitry Andric                  E->getOp() == AtomicExpr::AO__scoped_atomic_store_n;
12320b57cec5SDimitry Andric   bool IsLoad = E->getOp() == AtomicExpr::AO__c11_atomic_load ||
12330b57cec5SDimitry Andric                 E->getOp() == AtomicExpr::AO__opencl_atomic_load ||
12344824e7fdSDimitry Andric                 E->getOp() == AtomicExpr::AO__hip_atomic_load ||
12350b57cec5SDimitry Andric                 E->getOp() == AtomicExpr::AO__atomic_load ||
12365f757f3fSDimitry Andric                 E->getOp() == AtomicExpr::AO__atomic_load_n ||
12375f757f3fSDimitry Andric                 E->getOp() == AtomicExpr::AO__scoped_atomic_load ||
12385f757f3fSDimitry Andric                 E->getOp() == AtomicExpr::AO__scoped_atomic_load_n;
12390b57cec5SDimitry Andric 
12400b57cec5SDimitry Andric   if (isa<llvm::ConstantInt>(Order)) {
12410b57cec5SDimitry Andric     auto ord = cast<llvm::ConstantInt>(Order)->getZExtValue();
12420b57cec5SDimitry Andric     // We should not ever get to a case where the ordering isn't a valid C ABI
12430b57cec5SDimitry Andric     // value, but it's hard to enforce that in general.
12440b57cec5SDimitry Andric     if (llvm::isValidAtomicOrderingCABI(ord))
12450b57cec5SDimitry Andric       switch ((llvm::AtomicOrderingCABI)ord) {
12460b57cec5SDimitry Andric       case llvm::AtomicOrderingCABI::relaxed:
12470b57cec5SDimitry Andric         EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, IsWeak, OrderFail, Size,
12480b57cec5SDimitry Andric                      llvm::AtomicOrdering::Monotonic, Scope);
12490b57cec5SDimitry Andric         break;
12500b57cec5SDimitry Andric       case llvm::AtomicOrderingCABI::consume:
12510b57cec5SDimitry Andric       case llvm::AtomicOrderingCABI::acquire:
12520b57cec5SDimitry Andric         if (IsStore)
12530b57cec5SDimitry Andric           break; // Avoid crashing on code with undefined behavior
12540b57cec5SDimitry Andric         EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, IsWeak, OrderFail, Size,
12550b57cec5SDimitry Andric                      llvm::AtomicOrdering::Acquire, Scope);
12560b57cec5SDimitry Andric         break;
12570b57cec5SDimitry Andric       case llvm::AtomicOrderingCABI::release:
12580b57cec5SDimitry Andric         if (IsLoad)
12590b57cec5SDimitry Andric           break; // Avoid crashing on code with undefined behavior
12600b57cec5SDimitry Andric         EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, IsWeak, OrderFail, Size,
12610b57cec5SDimitry Andric                      llvm::AtomicOrdering::Release, Scope);
12620b57cec5SDimitry Andric         break;
12630b57cec5SDimitry Andric       case llvm::AtomicOrderingCABI::acq_rel:
12640b57cec5SDimitry Andric         if (IsLoad || IsStore)
12650b57cec5SDimitry Andric           break; // Avoid crashing on code with undefined behavior
12660b57cec5SDimitry Andric         EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, IsWeak, OrderFail, Size,
12670b57cec5SDimitry Andric                      llvm::AtomicOrdering::AcquireRelease, Scope);
12680b57cec5SDimitry Andric         break;
12690b57cec5SDimitry Andric       case llvm::AtomicOrderingCABI::seq_cst:
12700b57cec5SDimitry Andric         EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, IsWeak, OrderFail, Size,
12710b57cec5SDimitry Andric                      llvm::AtomicOrdering::SequentiallyConsistent, Scope);
12720b57cec5SDimitry Andric         break;
12730b57cec5SDimitry Andric       }
12740b57cec5SDimitry Andric     if (RValTy->isVoidType())
12750b57cec5SDimitry Andric       return RValue::get(nullptr);
12760b57cec5SDimitry Andric 
127706c3fb27SDimitry Andric     return convertTempToRValue(Dest.withElementType(ConvertTypeForMem(RValTy)),
12780b57cec5SDimitry Andric                                RValTy, E->getExprLoc());
12790b57cec5SDimitry Andric   }
12800b57cec5SDimitry Andric 
12810b57cec5SDimitry Andric   // Long case, when Order isn't obviously constant.
12820b57cec5SDimitry Andric 
12830b57cec5SDimitry Andric   // Create all the relevant BB's
12840b57cec5SDimitry Andric   llvm::BasicBlock *MonotonicBB = nullptr, *AcquireBB = nullptr,
12850b57cec5SDimitry Andric                    *ReleaseBB = nullptr, *AcqRelBB = nullptr,
12860b57cec5SDimitry Andric                    *SeqCstBB = nullptr;
12870b57cec5SDimitry Andric   MonotonicBB = createBasicBlock("monotonic", CurFn);
12880b57cec5SDimitry Andric   if (!IsStore)
12890b57cec5SDimitry Andric     AcquireBB = createBasicBlock("acquire", CurFn);
12900b57cec5SDimitry Andric   if (!IsLoad)
12910b57cec5SDimitry Andric     ReleaseBB = createBasicBlock("release", CurFn);
12920b57cec5SDimitry Andric   if (!IsLoad && !IsStore)
12930b57cec5SDimitry Andric     AcqRelBB = createBasicBlock("acqrel", CurFn);
12940b57cec5SDimitry Andric   SeqCstBB = createBasicBlock("seqcst", CurFn);
12950b57cec5SDimitry Andric   llvm::BasicBlock *ContBB = createBasicBlock("atomic.continue", CurFn);
12960b57cec5SDimitry Andric 
12970b57cec5SDimitry Andric   // Create the switch for the split
12980b57cec5SDimitry Andric   // MonotonicBB is arbitrarily chosen as the default case; in practice, this
12990b57cec5SDimitry Andric   // doesn't matter unless someone is crazy enough to use something that
13000b57cec5SDimitry Andric   // doesn't fold to a constant for the ordering.
13010b57cec5SDimitry Andric   Order = Builder.CreateIntCast(Order, Builder.getInt32Ty(), false);
13020b57cec5SDimitry Andric   llvm::SwitchInst *SI = Builder.CreateSwitch(Order, MonotonicBB);
13030b57cec5SDimitry Andric 
13040b57cec5SDimitry Andric   // Emit all the different atomics
13050b57cec5SDimitry Andric   Builder.SetInsertPoint(MonotonicBB);
13060b57cec5SDimitry Andric   EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, IsWeak, OrderFail, Size,
13070b57cec5SDimitry Andric                llvm::AtomicOrdering::Monotonic, Scope);
13080b57cec5SDimitry Andric   Builder.CreateBr(ContBB);
13090b57cec5SDimitry Andric   if (!IsStore) {
13100b57cec5SDimitry Andric     Builder.SetInsertPoint(AcquireBB);
13110b57cec5SDimitry Andric     EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, IsWeak, OrderFail, Size,
13120b57cec5SDimitry Andric                  llvm::AtomicOrdering::Acquire, Scope);
13130b57cec5SDimitry Andric     Builder.CreateBr(ContBB);
13140b57cec5SDimitry Andric     SI->addCase(Builder.getInt32((int)llvm::AtomicOrderingCABI::consume),
13150b57cec5SDimitry Andric                 AcquireBB);
13160b57cec5SDimitry Andric     SI->addCase(Builder.getInt32((int)llvm::AtomicOrderingCABI::acquire),
13170b57cec5SDimitry Andric                 AcquireBB);
13180b57cec5SDimitry Andric   }
13190b57cec5SDimitry Andric   if (!IsLoad) {
13200b57cec5SDimitry Andric     Builder.SetInsertPoint(ReleaseBB);
13210b57cec5SDimitry Andric     EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, IsWeak, OrderFail, Size,
13220b57cec5SDimitry Andric                  llvm::AtomicOrdering::Release, Scope);
13230b57cec5SDimitry Andric     Builder.CreateBr(ContBB);
13240b57cec5SDimitry Andric     SI->addCase(Builder.getInt32((int)llvm::AtomicOrderingCABI::release),
13250b57cec5SDimitry Andric                 ReleaseBB);
13260b57cec5SDimitry Andric   }
13270b57cec5SDimitry Andric   if (!IsLoad && !IsStore) {
13280b57cec5SDimitry Andric     Builder.SetInsertPoint(AcqRelBB);
13290b57cec5SDimitry Andric     EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, IsWeak, OrderFail, Size,
13300b57cec5SDimitry Andric                  llvm::AtomicOrdering::AcquireRelease, Scope);
13310b57cec5SDimitry Andric     Builder.CreateBr(ContBB);
13320b57cec5SDimitry Andric     SI->addCase(Builder.getInt32((int)llvm::AtomicOrderingCABI::acq_rel),
13330b57cec5SDimitry Andric                 AcqRelBB);
13340b57cec5SDimitry Andric   }
13350b57cec5SDimitry Andric   Builder.SetInsertPoint(SeqCstBB);
13360b57cec5SDimitry Andric   EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, IsWeak, OrderFail, Size,
13370b57cec5SDimitry Andric                llvm::AtomicOrdering::SequentiallyConsistent, Scope);
13380b57cec5SDimitry Andric   Builder.CreateBr(ContBB);
13390b57cec5SDimitry Andric   SI->addCase(Builder.getInt32((int)llvm::AtomicOrderingCABI::seq_cst),
13400b57cec5SDimitry Andric               SeqCstBB);
13410b57cec5SDimitry Andric 
13420b57cec5SDimitry Andric   // Cleanup and return
13430b57cec5SDimitry Andric   Builder.SetInsertPoint(ContBB);
13440b57cec5SDimitry Andric   if (RValTy->isVoidType())
13450b57cec5SDimitry Andric     return RValue::get(nullptr);
13460b57cec5SDimitry Andric 
13470b57cec5SDimitry Andric   assert(Atomics.getValueSizeInBits() <= Atomics.getAtomicSizeInBits());
134806c3fb27SDimitry Andric   return convertTempToRValue(Dest.withElementType(ConvertTypeForMem(RValTy)),
13490b57cec5SDimitry Andric                              RValTy, E->getExprLoc());
13500b57cec5SDimitry Andric }
13510b57cec5SDimitry Andric 
135206c3fb27SDimitry Andric Address AtomicInfo::castToAtomicIntPointer(Address addr) const {
13530b57cec5SDimitry Andric   llvm::IntegerType *ty =
13540b57cec5SDimitry Andric     llvm::IntegerType::get(CGF.getLLVMContext(), AtomicSizeInBits);
135506c3fb27SDimitry Andric   return addr.withElementType(ty);
13560b57cec5SDimitry Andric }
13570b57cec5SDimitry Andric 
13580b57cec5SDimitry Andric Address AtomicInfo::convertToAtomicIntPointer(Address Addr) const {
13590b57cec5SDimitry Andric   llvm::Type *Ty = Addr.getElementType();
13600b57cec5SDimitry Andric   uint64_t SourceSizeInBits = CGF.CGM.getDataLayout().getTypeSizeInBits(Ty);
13610b57cec5SDimitry Andric   if (SourceSizeInBits != AtomicSizeInBits) {
13620b57cec5SDimitry Andric     Address Tmp = CreateTempAlloca();
13630b57cec5SDimitry Andric     CGF.Builder.CreateMemCpy(Tmp, Addr,
13640b57cec5SDimitry Andric                              std::min(AtomicSizeInBits, SourceSizeInBits) / 8);
13650b57cec5SDimitry Andric     Addr = Tmp;
13660b57cec5SDimitry Andric   }
13670b57cec5SDimitry Andric 
136806c3fb27SDimitry Andric   return castToAtomicIntPointer(Addr);
13690b57cec5SDimitry Andric }
13700b57cec5SDimitry Andric 
13710b57cec5SDimitry Andric RValue AtomicInfo::convertAtomicTempToRValue(Address addr,
13720b57cec5SDimitry Andric                                              AggValueSlot resultSlot,
13730b57cec5SDimitry Andric                                              SourceLocation loc,
13740b57cec5SDimitry Andric                                              bool asValue) const {
13750b57cec5SDimitry Andric   if (LVal.isSimple()) {
13760b57cec5SDimitry Andric     if (EvaluationKind == TEK_Aggregate)
13770b57cec5SDimitry Andric       return resultSlot.asRValue();
13780b57cec5SDimitry Andric 
13790b57cec5SDimitry Andric     // Drill into the padding structure if we have one.
13800b57cec5SDimitry Andric     if (hasPadding())
13810b57cec5SDimitry Andric       addr = CGF.Builder.CreateStructGEP(addr, 0);
13820b57cec5SDimitry Andric 
13830b57cec5SDimitry Andric     // Otherwise, just convert the temporary to an r-value using the
13840b57cec5SDimitry Andric     // normal conversion routine.
13850b57cec5SDimitry Andric     return CGF.convertTempToRValue(addr, getValueType(), loc);
13860b57cec5SDimitry Andric   }
13870b57cec5SDimitry Andric   if (!asValue)
13880b57cec5SDimitry Andric     // Get RValue from temp memory as atomic for non-simple lvalues
13890b57cec5SDimitry Andric     return RValue::get(CGF.Builder.CreateLoad(addr));
13900b57cec5SDimitry Andric   if (LVal.isBitField())
13910b57cec5SDimitry Andric     return CGF.EmitLoadOfBitfieldLValue(
13920b57cec5SDimitry Andric         LValue::MakeBitfield(addr, LVal.getBitFieldInfo(), LVal.getType(),
13930b57cec5SDimitry Andric                              LVal.getBaseInfo(), TBAAAccessInfo()), loc);
13940b57cec5SDimitry Andric   if (LVal.isVectorElt())
13950b57cec5SDimitry Andric     return CGF.EmitLoadOfLValue(
13960b57cec5SDimitry Andric         LValue::MakeVectorElt(addr, LVal.getVectorIdx(), LVal.getType(),
13970b57cec5SDimitry Andric                               LVal.getBaseInfo(), TBAAAccessInfo()), loc);
13980b57cec5SDimitry Andric   assert(LVal.isExtVectorElt());
13990b57cec5SDimitry Andric   return CGF.EmitLoadOfExtVectorElementLValue(LValue::MakeExtVectorElt(
14000b57cec5SDimitry Andric       addr, LVal.getExtVectorElts(), LVal.getType(),
14010b57cec5SDimitry Andric       LVal.getBaseInfo(), TBAAAccessInfo()));
14020b57cec5SDimitry Andric }
14030b57cec5SDimitry Andric 
1404*0fca6ea1SDimitry Andric /// Return true if \param ValTy is a type that should be casted to integer
1405*0fca6ea1SDimitry Andric /// around the atomic memory operation. If \param CmpXchg is true, then the
1406*0fca6ea1SDimitry Andric /// cast of a floating point type is made as that instruction can not have
1407*0fca6ea1SDimitry Andric /// floating point operands.  TODO: Allow compare-and-exchange and FP - see
1408*0fca6ea1SDimitry Andric /// comment in AtomicExpandPass.cpp.
1409*0fca6ea1SDimitry Andric static bool shouldCastToInt(llvm::Type *ValTy, bool CmpXchg) {
1410*0fca6ea1SDimitry Andric   if (ValTy->isFloatingPointTy())
1411*0fca6ea1SDimitry Andric     return ValTy->isX86_FP80Ty() || CmpXchg;
1412*0fca6ea1SDimitry Andric   return !ValTy->isIntegerTy() && !ValTy->isPointerTy();
1413*0fca6ea1SDimitry Andric }
1414*0fca6ea1SDimitry Andric 
1415*0fca6ea1SDimitry Andric RValue AtomicInfo::ConvertToValueOrAtomic(llvm::Value *Val,
14160b57cec5SDimitry Andric                                           AggValueSlot ResultSlot,
1417*0fca6ea1SDimitry Andric                                           SourceLocation Loc, bool AsValue,
1418*0fca6ea1SDimitry Andric                                           bool CmpXchg) const {
14190b57cec5SDimitry Andric   // Try not to in some easy cases.
1420*0fca6ea1SDimitry Andric   assert((Val->getType()->isIntegerTy() || Val->getType()->isPointerTy() ||
1421*0fca6ea1SDimitry Andric           Val->getType()->isIEEELikeFPTy()) &&
1422*0fca6ea1SDimitry Andric          "Expected integer, pointer or floating point value when converting "
1423*0fca6ea1SDimitry Andric          "result.");
14240b57cec5SDimitry Andric   if (getEvaluationKind() == TEK_Scalar &&
14250b57cec5SDimitry Andric       (((!LVal.isBitField() ||
14260b57cec5SDimitry Andric          LVal.getBitFieldInfo().Size == ValueSizeInBits) &&
14270b57cec5SDimitry Andric         !hasPadding()) ||
14280b57cec5SDimitry Andric        !AsValue)) {
14290b57cec5SDimitry Andric     auto *ValTy = AsValue
14300b57cec5SDimitry Andric                       ? CGF.ConvertTypeForMem(ValueTy)
143104eeddc0SDimitry Andric                       : getAtomicAddress().getElementType();
1432*0fca6ea1SDimitry Andric     if (!shouldCastToInt(ValTy, CmpXchg)) {
1433*0fca6ea1SDimitry Andric       assert((!ValTy->isIntegerTy() || Val->getType() == ValTy) &&
1434*0fca6ea1SDimitry Andric              "Different integer types.");
1435*0fca6ea1SDimitry Andric       return RValue::get(CGF.EmitFromMemory(Val, ValueTy));
1436*0fca6ea1SDimitry Andric     }
1437*0fca6ea1SDimitry Andric     if (llvm::CastInst::isBitCastable(Val->getType(), ValTy))
1438*0fca6ea1SDimitry Andric       return RValue::get(CGF.Builder.CreateBitCast(Val, ValTy));
14390b57cec5SDimitry Andric   }
14400b57cec5SDimitry Andric 
14410b57cec5SDimitry Andric   // Create a temporary.  This needs to be big enough to hold the
14420b57cec5SDimitry Andric   // atomic integer.
14430b57cec5SDimitry Andric   Address Temp = Address::invalid();
14440b57cec5SDimitry Andric   bool TempIsVolatile = false;
14450b57cec5SDimitry Andric   if (AsValue && getEvaluationKind() == TEK_Aggregate) {
14460b57cec5SDimitry Andric     assert(!ResultSlot.isIgnored());
14470b57cec5SDimitry Andric     Temp = ResultSlot.getAddress();
14480b57cec5SDimitry Andric     TempIsVolatile = ResultSlot.isVolatile();
14490b57cec5SDimitry Andric   } else {
14500b57cec5SDimitry Andric     Temp = CreateTempAlloca();
14510b57cec5SDimitry Andric   }
14520b57cec5SDimitry Andric 
14530b57cec5SDimitry Andric   // Slam the integer into the temporary.
145406c3fb27SDimitry Andric   Address CastTemp = castToAtomicIntPointer(Temp);
1455*0fca6ea1SDimitry Andric   CGF.Builder.CreateStore(Val, CastTemp)->setVolatile(TempIsVolatile);
14560b57cec5SDimitry Andric 
14570b57cec5SDimitry Andric   return convertAtomicTempToRValue(Temp, ResultSlot, Loc, AsValue);
14580b57cec5SDimitry Andric }
14590b57cec5SDimitry Andric 
14600b57cec5SDimitry Andric void AtomicInfo::EmitAtomicLoadLibcall(llvm::Value *AddForLoaded,
14610b57cec5SDimitry Andric                                        llvm::AtomicOrdering AO, bool) {
14620b57cec5SDimitry Andric   // void __atomic_load(size_t size, void *mem, void *return, int order);
14630b57cec5SDimitry Andric   CallArgList Args;
14640b57cec5SDimitry Andric   Args.add(RValue::get(getAtomicSizeValue()), CGF.getContext().getSizeType());
146506c3fb27SDimitry Andric   Args.add(RValue::get(getAtomicPointer()), CGF.getContext().VoidPtrTy);
146606c3fb27SDimitry Andric   Args.add(RValue::get(AddForLoaded), CGF.getContext().VoidPtrTy);
14670b57cec5SDimitry Andric   Args.add(
14680b57cec5SDimitry Andric       RValue::get(llvm::ConstantInt::get(CGF.IntTy, (int)llvm::toCABI(AO))),
14690b57cec5SDimitry Andric       CGF.getContext().IntTy);
14700b57cec5SDimitry Andric   emitAtomicLibcall(CGF, "__atomic_load", CGF.getContext().VoidTy, Args);
14710b57cec5SDimitry Andric }
14720b57cec5SDimitry Andric 
14730b57cec5SDimitry Andric llvm::Value *AtomicInfo::EmitAtomicLoadOp(llvm::AtomicOrdering AO,
1474*0fca6ea1SDimitry Andric                                           bool IsVolatile, bool CmpXchg) {
14750b57cec5SDimitry Andric   // Okay, we're doing this natively.
1476*0fca6ea1SDimitry Andric   Address Addr = getAtomicAddress();
1477*0fca6ea1SDimitry Andric   if (shouldCastToInt(Addr.getElementType(), CmpXchg))
1478*0fca6ea1SDimitry Andric     Addr = castToAtomicIntPointer(Addr);
14790b57cec5SDimitry Andric   llvm::LoadInst *Load = CGF.Builder.CreateLoad(Addr, "atomic-load");
14800b57cec5SDimitry Andric   Load->setAtomic(AO);
14810b57cec5SDimitry Andric 
14820b57cec5SDimitry Andric   // Other decoration.
14830b57cec5SDimitry Andric   if (IsVolatile)
14840b57cec5SDimitry Andric     Load->setVolatile(true);
14850b57cec5SDimitry Andric   CGF.CGM.DecorateInstructionWithTBAA(Load, LVal.getTBAAInfo());
14860b57cec5SDimitry Andric   return Load;
14870b57cec5SDimitry Andric }
14880b57cec5SDimitry Andric 
14890b57cec5SDimitry Andric /// An LValue is a candidate for having its loads and stores be made atomic if
14900b57cec5SDimitry Andric /// we are operating under /volatile:ms *and* the LValue itself is volatile and
14910b57cec5SDimitry Andric /// performing such an operation can be performed without a libcall.
14920b57cec5SDimitry Andric bool CodeGenFunction::LValueIsSuitableForInlineAtomic(LValue LV) {
1493bdd1243dSDimitry Andric   if (!CGM.getLangOpts().MSVolatile) return false;
14940b57cec5SDimitry Andric   AtomicInfo AI(*this, LV);
14950b57cec5SDimitry Andric   bool IsVolatile = LV.isVolatile() || hasVolatileMember(LV.getType());
14960b57cec5SDimitry Andric   // An atomic is inline if we don't need to use a libcall.
14970b57cec5SDimitry Andric   bool AtomicIsInline = !AI.shouldUseLibcall();
14980b57cec5SDimitry Andric   // MSVC doesn't seem to do this for types wider than a pointer.
14990b57cec5SDimitry Andric   if (getContext().getTypeSize(LV.getType()) >
15000b57cec5SDimitry Andric       getContext().getTypeSize(getContext().getIntPtrType()))
15010b57cec5SDimitry Andric     return false;
15020b57cec5SDimitry Andric   return IsVolatile && AtomicIsInline;
15030b57cec5SDimitry Andric }
15040b57cec5SDimitry Andric 
15050b57cec5SDimitry Andric RValue CodeGenFunction::EmitAtomicLoad(LValue LV, SourceLocation SL,
15060b57cec5SDimitry Andric                                        AggValueSlot Slot) {
15070b57cec5SDimitry Andric   llvm::AtomicOrdering AO;
15080b57cec5SDimitry Andric   bool IsVolatile = LV.isVolatileQualified();
15090b57cec5SDimitry Andric   if (LV.getType()->isAtomicType()) {
15100b57cec5SDimitry Andric     AO = llvm::AtomicOrdering::SequentiallyConsistent;
15110b57cec5SDimitry Andric   } else {
15120b57cec5SDimitry Andric     AO = llvm::AtomicOrdering::Acquire;
15130b57cec5SDimitry Andric     IsVolatile = true;
15140b57cec5SDimitry Andric   }
15150b57cec5SDimitry Andric   return EmitAtomicLoad(LV, SL, AO, IsVolatile, Slot);
15160b57cec5SDimitry Andric }
15170b57cec5SDimitry Andric 
15180b57cec5SDimitry Andric RValue AtomicInfo::EmitAtomicLoad(AggValueSlot ResultSlot, SourceLocation Loc,
15190b57cec5SDimitry Andric                                   bool AsValue, llvm::AtomicOrdering AO,
15200b57cec5SDimitry Andric                                   bool IsVolatile) {
15210b57cec5SDimitry Andric   // Check whether we should use a library call.
15220b57cec5SDimitry Andric   if (shouldUseLibcall()) {
15230b57cec5SDimitry Andric     Address TempAddr = Address::invalid();
15240b57cec5SDimitry Andric     if (LVal.isSimple() && !ResultSlot.isIgnored()) {
15250b57cec5SDimitry Andric       assert(getEvaluationKind() == TEK_Aggregate);
15260b57cec5SDimitry Andric       TempAddr = ResultSlot.getAddress();
15270b57cec5SDimitry Andric     } else
15280b57cec5SDimitry Andric       TempAddr = CreateTempAlloca();
15290b57cec5SDimitry Andric 
1530*0fca6ea1SDimitry Andric     EmitAtomicLoadLibcall(TempAddr.emitRawPointer(CGF), AO, IsVolatile);
15310b57cec5SDimitry Andric 
15320b57cec5SDimitry Andric     // Okay, turn that back into the original value or whole atomic (for
15330b57cec5SDimitry Andric     // non-simple lvalues) type.
15340b57cec5SDimitry Andric     return convertAtomicTempToRValue(TempAddr, ResultSlot, Loc, AsValue);
15350b57cec5SDimitry Andric   }
15360b57cec5SDimitry Andric 
15370b57cec5SDimitry Andric   // Okay, we're doing this natively.
15380b57cec5SDimitry Andric   auto *Load = EmitAtomicLoadOp(AO, IsVolatile);
15390b57cec5SDimitry Andric 
15400b57cec5SDimitry Andric   // If we're ignoring an aggregate return, don't do anything.
15410b57cec5SDimitry Andric   if (getEvaluationKind() == TEK_Aggregate && ResultSlot.isIgnored())
15420b57cec5SDimitry Andric     return RValue::getAggregate(Address::invalid(), false);
15430b57cec5SDimitry Andric 
15440b57cec5SDimitry Andric   // Okay, turn that back into the original value or atomic (for non-simple
15450b57cec5SDimitry Andric   // lvalues) type.
1546*0fca6ea1SDimitry Andric   return ConvertToValueOrAtomic(Load, ResultSlot, Loc, AsValue);
15470b57cec5SDimitry Andric }
15480b57cec5SDimitry Andric 
15490b57cec5SDimitry Andric /// Emit a load from an l-value of atomic type.  Note that the r-value
15500b57cec5SDimitry Andric /// we produce is an r-value of the atomic *value* type.
15510b57cec5SDimitry Andric RValue CodeGenFunction::EmitAtomicLoad(LValue src, SourceLocation loc,
15520b57cec5SDimitry Andric                                        llvm::AtomicOrdering AO, bool IsVolatile,
15530b57cec5SDimitry Andric                                        AggValueSlot resultSlot) {
15540b57cec5SDimitry Andric   AtomicInfo Atomics(*this, src);
15550b57cec5SDimitry Andric   return Atomics.EmitAtomicLoad(resultSlot, loc, /*AsValue=*/true, AO,
15560b57cec5SDimitry Andric                                 IsVolatile);
15570b57cec5SDimitry Andric }
15580b57cec5SDimitry Andric 
15590b57cec5SDimitry Andric /// Copy an r-value into memory as part of storing to an atomic type.
15600b57cec5SDimitry Andric /// This needs to create a bit-pattern suitable for atomic operations.
15610b57cec5SDimitry Andric void AtomicInfo::emitCopyIntoMemory(RValue rvalue) const {
15620b57cec5SDimitry Andric   assert(LVal.isSimple());
15630b57cec5SDimitry Andric   // If we have an r-value, the rvalue should be of the atomic type,
15640b57cec5SDimitry Andric   // which means that the caller is responsible for having zeroed
15650b57cec5SDimitry Andric   // any padding.  Just do an aggregate copy of that type.
15660b57cec5SDimitry Andric   if (rvalue.isAggregate()) {
15670b57cec5SDimitry Andric     LValue Dest = CGF.MakeAddrLValue(getAtomicAddress(), getAtomicType());
15680b57cec5SDimitry Andric     LValue Src = CGF.MakeAddrLValue(rvalue.getAggregateAddress(),
15690b57cec5SDimitry Andric                                     getAtomicType());
15700b57cec5SDimitry Andric     bool IsVolatile = rvalue.isVolatileQualified() ||
15710b57cec5SDimitry Andric                       LVal.isVolatileQualified();
15720b57cec5SDimitry Andric     CGF.EmitAggregateCopy(Dest, Src, getAtomicType(),
15730b57cec5SDimitry Andric                           AggValueSlot::DoesNotOverlap, IsVolatile);
15740b57cec5SDimitry Andric     return;
15750b57cec5SDimitry Andric   }
15760b57cec5SDimitry Andric 
15770b57cec5SDimitry Andric   // Okay, otherwise we're copying stuff.
15780b57cec5SDimitry Andric 
15790b57cec5SDimitry Andric   // Zero out the buffer if necessary.
15800b57cec5SDimitry Andric   emitMemSetZeroIfNecessary();
15810b57cec5SDimitry Andric 
15820b57cec5SDimitry Andric   // Drill past the padding if present.
15830b57cec5SDimitry Andric   LValue TempLVal = projectValue();
15840b57cec5SDimitry Andric 
15850b57cec5SDimitry Andric   // Okay, store the rvalue in.
15860b57cec5SDimitry Andric   if (rvalue.isScalar()) {
15870b57cec5SDimitry Andric     CGF.EmitStoreOfScalar(rvalue.getScalarVal(), TempLVal, /*init*/ true);
15880b57cec5SDimitry Andric   } else {
15890b57cec5SDimitry Andric     CGF.EmitStoreOfComplex(rvalue.getComplexVal(), TempLVal, /*init*/ true);
15900b57cec5SDimitry Andric   }
15910b57cec5SDimitry Andric }
15920b57cec5SDimitry Andric 
15930b57cec5SDimitry Andric 
15940b57cec5SDimitry Andric /// Materialize an r-value into memory for the purposes of storing it
15950b57cec5SDimitry Andric /// to an atomic type.
15960b57cec5SDimitry Andric Address AtomicInfo::materializeRValue(RValue rvalue) const {
15970b57cec5SDimitry Andric   // Aggregate r-values are already in memory, and EmitAtomicStore
15980b57cec5SDimitry Andric   // requires them to be values of the atomic type.
15990b57cec5SDimitry Andric   if (rvalue.isAggregate())
16000b57cec5SDimitry Andric     return rvalue.getAggregateAddress();
16010b57cec5SDimitry Andric 
16020b57cec5SDimitry Andric   // Otherwise, make a temporary and materialize into it.
16030b57cec5SDimitry Andric   LValue TempLV = CGF.MakeAddrLValue(CreateTempAlloca(), getAtomicType());
16040b57cec5SDimitry Andric   AtomicInfo Atomics(CGF, TempLV);
16050b57cec5SDimitry Andric   Atomics.emitCopyIntoMemory(rvalue);
1606*0fca6ea1SDimitry Andric   return TempLV.getAddress();
16070b57cec5SDimitry Andric }
16080b57cec5SDimitry Andric 
1609*0fca6ea1SDimitry Andric llvm::Value *AtomicInfo::getScalarRValValueOrNull(RValue RVal) const {
1610*0fca6ea1SDimitry Andric   if (RVal.isScalar() && (!hasPadding() || !LVal.isSimple()))
1611*0fca6ea1SDimitry Andric     return RVal.getScalarVal();
1612*0fca6ea1SDimitry Andric   return nullptr;
1613*0fca6ea1SDimitry Andric }
1614*0fca6ea1SDimitry Andric 
1615*0fca6ea1SDimitry Andric llvm::Value *AtomicInfo::convertRValueToInt(RValue RVal, bool CmpXchg) const {
16160b57cec5SDimitry Andric   // If we've got a scalar value of the right size, try to avoid going
1617*0fca6ea1SDimitry Andric   // through memory. Floats get casted if needed by AtomicExpandPass.
1618*0fca6ea1SDimitry Andric   if (llvm::Value *Value = getScalarRValValueOrNull(RVal)) {
1619*0fca6ea1SDimitry Andric     if (!shouldCastToInt(Value->getType(), CmpXchg))
16200b57cec5SDimitry Andric       return CGF.EmitToMemory(Value, ValueTy);
16210b57cec5SDimitry Andric     else {
16220b57cec5SDimitry Andric       llvm::IntegerType *InputIntTy = llvm::IntegerType::get(
16230b57cec5SDimitry Andric           CGF.getLLVMContext(),
16240b57cec5SDimitry Andric           LVal.isSimple() ? getValueSizeInBits() : getAtomicSizeInBits());
1625*0fca6ea1SDimitry Andric       if (llvm::BitCastInst::isBitCastable(Value->getType(), InputIntTy))
16260b57cec5SDimitry Andric         return CGF.Builder.CreateBitCast(Value, InputIntTy);
16270b57cec5SDimitry Andric     }
16280b57cec5SDimitry Andric   }
16290b57cec5SDimitry Andric   // Otherwise, we need to go through memory.
16300b57cec5SDimitry Andric   // Put the r-value in memory.
16310b57cec5SDimitry Andric   Address Addr = materializeRValue(RVal);
16320b57cec5SDimitry Andric 
16330b57cec5SDimitry Andric   // Cast the temporary to the atomic int type and pull a value out.
163406c3fb27SDimitry Andric   Addr = castToAtomicIntPointer(Addr);
16350b57cec5SDimitry Andric   return CGF.Builder.CreateLoad(Addr);
16360b57cec5SDimitry Andric }
16370b57cec5SDimitry Andric 
16380b57cec5SDimitry Andric std::pair<llvm::Value *, llvm::Value *> AtomicInfo::EmitAtomicCompareExchangeOp(
16390b57cec5SDimitry Andric     llvm::Value *ExpectedVal, llvm::Value *DesiredVal,
16400b57cec5SDimitry Andric     llvm::AtomicOrdering Success, llvm::AtomicOrdering Failure, bool IsWeak) {
16410b57cec5SDimitry Andric   // Do the atomic store.
16420b57cec5SDimitry Andric   Address Addr = getAtomicAddressAsAtomicIntPointer();
16435f757f3fSDimitry Andric   auto *Inst = CGF.Builder.CreateAtomicCmpXchg(Addr, ExpectedVal, DesiredVal,
16440b57cec5SDimitry Andric                                                Success, Failure);
16450b57cec5SDimitry Andric   // Other decoration.
16460b57cec5SDimitry Andric   Inst->setVolatile(LVal.isVolatileQualified());
16470b57cec5SDimitry Andric   Inst->setWeak(IsWeak);
16480b57cec5SDimitry Andric 
16490b57cec5SDimitry Andric   // Okay, turn that back into the original value type.
16500b57cec5SDimitry Andric   auto *PreviousVal = CGF.Builder.CreateExtractValue(Inst, /*Idxs=*/0);
16510b57cec5SDimitry Andric   auto *SuccessFailureVal = CGF.Builder.CreateExtractValue(Inst, /*Idxs=*/1);
16520b57cec5SDimitry Andric   return std::make_pair(PreviousVal, SuccessFailureVal);
16530b57cec5SDimitry Andric }
16540b57cec5SDimitry Andric 
16550b57cec5SDimitry Andric llvm::Value *
16560b57cec5SDimitry Andric AtomicInfo::EmitAtomicCompareExchangeLibcall(llvm::Value *ExpectedAddr,
16570b57cec5SDimitry Andric                                              llvm::Value *DesiredAddr,
16580b57cec5SDimitry Andric                                              llvm::AtomicOrdering Success,
16590b57cec5SDimitry Andric                                              llvm::AtomicOrdering Failure) {
16600b57cec5SDimitry Andric   // bool __atomic_compare_exchange(size_t size, void *obj, void *expected,
16610b57cec5SDimitry Andric   // void *desired, int success, int failure);
16620b57cec5SDimitry Andric   CallArgList Args;
16630b57cec5SDimitry Andric   Args.add(RValue::get(getAtomicSizeValue()), CGF.getContext().getSizeType());
166406c3fb27SDimitry Andric   Args.add(RValue::get(getAtomicPointer()), CGF.getContext().VoidPtrTy);
166506c3fb27SDimitry Andric   Args.add(RValue::get(ExpectedAddr), CGF.getContext().VoidPtrTy);
166606c3fb27SDimitry Andric   Args.add(RValue::get(DesiredAddr), CGF.getContext().VoidPtrTy);
16670b57cec5SDimitry Andric   Args.add(RValue::get(
16680b57cec5SDimitry Andric                llvm::ConstantInt::get(CGF.IntTy, (int)llvm::toCABI(Success))),
16690b57cec5SDimitry Andric            CGF.getContext().IntTy);
16700b57cec5SDimitry Andric   Args.add(RValue::get(
16710b57cec5SDimitry Andric                llvm::ConstantInt::get(CGF.IntTy, (int)llvm::toCABI(Failure))),
16720b57cec5SDimitry Andric            CGF.getContext().IntTy);
16730b57cec5SDimitry Andric   auto SuccessFailureRVal = emitAtomicLibcall(CGF, "__atomic_compare_exchange",
16740b57cec5SDimitry Andric                                               CGF.getContext().BoolTy, Args);
16750b57cec5SDimitry Andric 
16760b57cec5SDimitry Andric   return SuccessFailureRVal.getScalarVal();
16770b57cec5SDimitry Andric }
16780b57cec5SDimitry Andric 
16790b57cec5SDimitry Andric std::pair<RValue, llvm::Value *> AtomicInfo::EmitAtomicCompareExchange(
16800b57cec5SDimitry Andric     RValue Expected, RValue Desired, llvm::AtomicOrdering Success,
16810b57cec5SDimitry Andric     llvm::AtomicOrdering Failure, bool IsWeak) {
16820b57cec5SDimitry Andric   // Check whether we should use a library call.
16830b57cec5SDimitry Andric   if (shouldUseLibcall()) {
16840b57cec5SDimitry Andric     // Produce a source address.
16850b57cec5SDimitry Andric     Address ExpectedAddr = materializeRValue(Expected);
1686*0fca6ea1SDimitry Andric     llvm::Value *ExpectedPtr = ExpectedAddr.emitRawPointer(CGF);
1687*0fca6ea1SDimitry Andric     llvm::Value *DesiredPtr = materializeRValue(Desired).emitRawPointer(CGF);
1688*0fca6ea1SDimitry Andric     auto *Res = EmitAtomicCompareExchangeLibcall(ExpectedPtr, DesiredPtr,
16890b57cec5SDimitry Andric                                                  Success, Failure);
16900b57cec5SDimitry Andric     return std::make_pair(
16910b57cec5SDimitry Andric         convertAtomicTempToRValue(ExpectedAddr, AggValueSlot::ignored(),
16920b57cec5SDimitry Andric                                   SourceLocation(), /*AsValue=*/false),
16930b57cec5SDimitry Andric         Res);
16940b57cec5SDimitry Andric   }
16950b57cec5SDimitry Andric 
16960b57cec5SDimitry Andric   // If we've got a scalar value of the right size, try to avoid going
16970b57cec5SDimitry Andric   // through memory.
1698*0fca6ea1SDimitry Andric   auto *ExpectedVal = convertRValueToInt(Expected, /*CmpXchg=*/true);
1699*0fca6ea1SDimitry Andric   auto *DesiredVal = convertRValueToInt(Desired, /*CmpXchg=*/true);
17000b57cec5SDimitry Andric   auto Res = EmitAtomicCompareExchangeOp(ExpectedVal, DesiredVal, Success,
17010b57cec5SDimitry Andric                                          Failure, IsWeak);
17020b57cec5SDimitry Andric   return std::make_pair(
1703*0fca6ea1SDimitry Andric       ConvertToValueOrAtomic(Res.first, AggValueSlot::ignored(),
1704*0fca6ea1SDimitry Andric                              SourceLocation(), /*AsValue=*/false,
1705*0fca6ea1SDimitry Andric                              /*CmpXchg=*/true),
17060b57cec5SDimitry Andric       Res.second);
17070b57cec5SDimitry Andric }
17080b57cec5SDimitry Andric 
17090b57cec5SDimitry Andric static void
17100b57cec5SDimitry Andric EmitAtomicUpdateValue(CodeGenFunction &CGF, AtomicInfo &Atomics, RValue OldRVal,
17110b57cec5SDimitry Andric                       const llvm::function_ref<RValue(RValue)> &UpdateOp,
17120b57cec5SDimitry Andric                       Address DesiredAddr) {
17130b57cec5SDimitry Andric   RValue UpRVal;
17140b57cec5SDimitry Andric   LValue AtomicLVal = Atomics.getAtomicLValue();
17150b57cec5SDimitry Andric   LValue DesiredLVal;
17160b57cec5SDimitry Andric   if (AtomicLVal.isSimple()) {
17170b57cec5SDimitry Andric     UpRVal = OldRVal;
17180b57cec5SDimitry Andric     DesiredLVal = CGF.MakeAddrLValue(DesiredAddr, AtomicLVal.getType());
17190b57cec5SDimitry Andric   } else {
17200b57cec5SDimitry Andric     // Build new lvalue for temp address.
17210b57cec5SDimitry Andric     Address Ptr = Atomics.materializeRValue(OldRVal);
17220b57cec5SDimitry Andric     LValue UpdateLVal;
17230b57cec5SDimitry Andric     if (AtomicLVal.isBitField()) {
17240b57cec5SDimitry Andric       UpdateLVal =
17250b57cec5SDimitry Andric           LValue::MakeBitfield(Ptr, AtomicLVal.getBitFieldInfo(),
17260b57cec5SDimitry Andric                                AtomicLVal.getType(),
17270b57cec5SDimitry Andric                                AtomicLVal.getBaseInfo(),
17280b57cec5SDimitry Andric                                AtomicLVal.getTBAAInfo());
17290b57cec5SDimitry Andric       DesiredLVal =
17300b57cec5SDimitry Andric           LValue::MakeBitfield(DesiredAddr, AtomicLVal.getBitFieldInfo(),
17310b57cec5SDimitry Andric                                AtomicLVal.getType(), AtomicLVal.getBaseInfo(),
17320b57cec5SDimitry Andric                                AtomicLVal.getTBAAInfo());
17330b57cec5SDimitry Andric     } else if (AtomicLVal.isVectorElt()) {
17340b57cec5SDimitry Andric       UpdateLVal = LValue::MakeVectorElt(Ptr, AtomicLVal.getVectorIdx(),
17350b57cec5SDimitry Andric                                          AtomicLVal.getType(),
17360b57cec5SDimitry Andric                                          AtomicLVal.getBaseInfo(),
17370b57cec5SDimitry Andric                                          AtomicLVal.getTBAAInfo());
17380b57cec5SDimitry Andric       DesiredLVal = LValue::MakeVectorElt(
17390b57cec5SDimitry Andric           DesiredAddr, AtomicLVal.getVectorIdx(), AtomicLVal.getType(),
17400b57cec5SDimitry Andric           AtomicLVal.getBaseInfo(), AtomicLVal.getTBAAInfo());
17410b57cec5SDimitry Andric     } else {
17420b57cec5SDimitry Andric       assert(AtomicLVal.isExtVectorElt());
17430b57cec5SDimitry Andric       UpdateLVal = LValue::MakeExtVectorElt(Ptr, AtomicLVal.getExtVectorElts(),
17440b57cec5SDimitry Andric                                             AtomicLVal.getType(),
17450b57cec5SDimitry Andric                                             AtomicLVal.getBaseInfo(),
17460b57cec5SDimitry Andric                                             AtomicLVal.getTBAAInfo());
17470b57cec5SDimitry Andric       DesiredLVal = LValue::MakeExtVectorElt(
17480b57cec5SDimitry Andric           DesiredAddr, AtomicLVal.getExtVectorElts(), AtomicLVal.getType(),
17490b57cec5SDimitry Andric           AtomicLVal.getBaseInfo(), AtomicLVal.getTBAAInfo());
17500b57cec5SDimitry Andric     }
17510b57cec5SDimitry Andric     UpRVal = CGF.EmitLoadOfLValue(UpdateLVal, SourceLocation());
17520b57cec5SDimitry Andric   }
17530b57cec5SDimitry Andric   // Store new value in the corresponding memory area.
17540b57cec5SDimitry Andric   RValue NewRVal = UpdateOp(UpRVal);
17550b57cec5SDimitry Andric   if (NewRVal.isScalar()) {
17560b57cec5SDimitry Andric     CGF.EmitStoreThroughLValue(NewRVal, DesiredLVal);
17570b57cec5SDimitry Andric   } else {
17580b57cec5SDimitry Andric     assert(NewRVal.isComplex());
17590b57cec5SDimitry Andric     CGF.EmitStoreOfComplex(NewRVal.getComplexVal(), DesiredLVal,
17600b57cec5SDimitry Andric                            /*isInit=*/false);
17610b57cec5SDimitry Andric   }
17620b57cec5SDimitry Andric }
17630b57cec5SDimitry Andric 
17640b57cec5SDimitry Andric void AtomicInfo::EmitAtomicUpdateLibcall(
17650b57cec5SDimitry Andric     llvm::AtomicOrdering AO, const llvm::function_ref<RValue(RValue)> &UpdateOp,
17660b57cec5SDimitry Andric     bool IsVolatile) {
17670b57cec5SDimitry Andric   auto Failure = llvm::AtomicCmpXchgInst::getStrongestFailureOrdering(AO);
17680b57cec5SDimitry Andric 
17690b57cec5SDimitry Andric   Address ExpectedAddr = CreateTempAlloca();
17700b57cec5SDimitry Andric 
1771*0fca6ea1SDimitry Andric   EmitAtomicLoadLibcall(ExpectedAddr.emitRawPointer(CGF), AO, IsVolatile);
17720b57cec5SDimitry Andric   auto *ContBB = CGF.createBasicBlock("atomic_cont");
17730b57cec5SDimitry Andric   auto *ExitBB = CGF.createBasicBlock("atomic_exit");
17740b57cec5SDimitry Andric   CGF.EmitBlock(ContBB);
17750b57cec5SDimitry Andric   Address DesiredAddr = CreateTempAlloca();
17760b57cec5SDimitry Andric   if ((LVal.isBitField() && BFI.Size != ValueSizeInBits) ||
17770b57cec5SDimitry Andric       requiresMemSetZero(getAtomicAddress().getElementType())) {
17780b57cec5SDimitry Andric     auto *OldVal = CGF.Builder.CreateLoad(ExpectedAddr);
17790b57cec5SDimitry Andric     CGF.Builder.CreateStore(OldVal, DesiredAddr);
17800b57cec5SDimitry Andric   }
17810b57cec5SDimitry Andric   auto OldRVal = convertAtomicTempToRValue(ExpectedAddr,
17820b57cec5SDimitry Andric                                            AggValueSlot::ignored(),
17830b57cec5SDimitry Andric                                            SourceLocation(), /*AsValue=*/false);
17840b57cec5SDimitry Andric   EmitAtomicUpdateValue(CGF, *this, OldRVal, UpdateOp, DesiredAddr);
1785*0fca6ea1SDimitry Andric   llvm::Value *ExpectedPtr = ExpectedAddr.emitRawPointer(CGF);
1786*0fca6ea1SDimitry Andric   llvm::Value *DesiredPtr = DesiredAddr.emitRawPointer(CGF);
17870b57cec5SDimitry Andric   auto *Res =
1788*0fca6ea1SDimitry Andric       EmitAtomicCompareExchangeLibcall(ExpectedPtr, DesiredPtr, AO, Failure);
17890b57cec5SDimitry Andric   CGF.Builder.CreateCondBr(Res, ExitBB, ContBB);
17900b57cec5SDimitry Andric   CGF.EmitBlock(ExitBB, /*IsFinished=*/true);
17910b57cec5SDimitry Andric }
17920b57cec5SDimitry Andric 
17930b57cec5SDimitry Andric void AtomicInfo::EmitAtomicUpdateOp(
17940b57cec5SDimitry Andric     llvm::AtomicOrdering AO, const llvm::function_ref<RValue(RValue)> &UpdateOp,
17950b57cec5SDimitry Andric     bool IsVolatile) {
17960b57cec5SDimitry Andric   auto Failure = llvm::AtomicCmpXchgInst::getStrongestFailureOrdering(AO);
17970b57cec5SDimitry Andric 
17980b57cec5SDimitry Andric   // Do the atomic load.
1799*0fca6ea1SDimitry Andric   auto *OldVal = EmitAtomicLoadOp(Failure, IsVolatile, /*CmpXchg=*/true);
18000b57cec5SDimitry Andric   // For non-simple lvalues perform compare-and-swap procedure.
18010b57cec5SDimitry Andric   auto *ContBB = CGF.createBasicBlock("atomic_cont");
18020b57cec5SDimitry Andric   auto *ExitBB = CGF.createBasicBlock("atomic_exit");
18030b57cec5SDimitry Andric   auto *CurBB = CGF.Builder.GetInsertBlock();
18040b57cec5SDimitry Andric   CGF.EmitBlock(ContBB);
18050b57cec5SDimitry Andric   llvm::PHINode *PHI = CGF.Builder.CreatePHI(OldVal->getType(),
18060b57cec5SDimitry Andric                                              /*NumReservedValues=*/2);
18070b57cec5SDimitry Andric   PHI->addIncoming(OldVal, CurBB);
18080b57cec5SDimitry Andric   Address NewAtomicAddr = CreateTempAlloca();
1809*0fca6ea1SDimitry Andric   Address NewAtomicIntAddr =
1810*0fca6ea1SDimitry Andric       shouldCastToInt(NewAtomicAddr.getElementType(), /*CmpXchg=*/true)
1811*0fca6ea1SDimitry Andric           ? castToAtomicIntPointer(NewAtomicAddr)
1812*0fca6ea1SDimitry Andric           : NewAtomicAddr;
1813*0fca6ea1SDimitry Andric 
18140b57cec5SDimitry Andric   if ((LVal.isBitField() && BFI.Size != ValueSizeInBits) ||
18150b57cec5SDimitry Andric       requiresMemSetZero(getAtomicAddress().getElementType())) {
18160b57cec5SDimitry Andric     CGF.Builder.CreateStore(PHI, NewAtomicIntAddr);
18170b57cec5SDimitry Andric   }
1818*0fca6ea1SDimitry Andric   auto OldRVal = ConvertToValueOrAtomic(PHI, AggValueSlot::ignored(),
1819*0fca6ea1SDimitry Andric                                         SourceLocation(), /*AsValue=*/false,
1820*0fca6ea1SDimitry Andric                                         /*CmpXchg=*/true);
18210b57cec5SDimitry Andric   EmitAtomicUpdateValue(CGF, *this, OldRVal, UpdateOp, NewAtomicAddr);
18220b57cec5SDimitry Andric   auto *DesiredVal = CGF.Builder.CreateLoad(NewAtomicIntAddr);
18230b57cec5SDimitry Andric   // Try to write new value using cmpxchg operation.
18240b57cec5SDimitry Andric   auto Res = EmitAtomicCompareExchangeOp(PHI, DesiredVal, AO, Failure);
18250b57cec5SDimitry Andric   PHI->addIncoming(Res.first, CGF.Builder.GetInsertBlock());
18260b57cec5SDimitry Andric   CGF.Builder.CreateCondBr(Res.second, ExitBB, ContBB);
18270b57cec5SDimitry Andric   CGF.EmitBlock(ExitBB, /*IsFinished=*/true);
18280b57cec5SDimitry Andric }
18290b57cec5SDimitry Andric 
18300b57cec5SDimitry Andric static void EmitAtomicUpdateValue(CodeGenFunction &CGF, AtomicInfo &Atomics,
18310b57cec5SDimitry Andric                                   RValue UpdateRVal, Address DesiredAddr) {
18320b57cec5SDimitry Andric   LValue AtomicLVal = Atomics.getAtomicLValue();
18330b57cec5SDimitry Andric   LValue DesiredLVal;
18340b57cec5SDimitry Andric   // Build new lvalue for temp address.
18350b57cec5SDimitry Andric   if (AtomicLVal.isBitField()) {
18360b57cec5SDimitry Andric     DesiredLVal =
18370b57cec5SDimitry Andric         LValue::MakeBitfield(DesiredAddr, AtomicLVal.getBitFieldInfo(),
18380b57cec5SDimitry Andric                              AtomicLVal.getType(), AtomicLVal.getBaseInfo(),
18390b57cec5SDimitry Andric                              AtomicLVal.getTBAAInfo());
18400b57cec5SDimitry Andric   } else if (AtomicLVal.isVectorElt()) {
18410b57cec5SDimitry Andric     DesiredLVal =
18420b57cec5SDimitry Andric         LValue::MakeVectorElt(DesiredAddr, AtomicLVal.getVectorIdx(),
18430b57cec5SDimitry Andric                               AtomicLVal.getType(), AtomicLVal.getBaseInfo(),
18440b57cec5SDimitry Andric                               AtomicLVal.getTBAAInfo());
18450b57cec5SDimitry Andric   } else {
18460b57cec5SDimitry Andric     assert(AtomicLVal.isExtVectorElt());
18470b57cec5SDimitry Andric     DesiredLVal = LValue::MakeExtVectorElt(
18480b57cec5SDimitry Andric         DesiredAddr, AtomicLVal.getExtVectorElts(), AtomicLVal.getType(),
18490b57cec5SDimitry Andric         AtomicLVal.getBaseInfo(), AtomicLVal.getTBAAInfo());
18500b57cec5SDimitry Andric   }
18510b57cec5SDimitry Andric   // Store new value in the corresponding memory area.
18520b57cec5SDimitry Andric   assert(UpdateRVal.isScalar());
18530b57cec5SDimitry Andric   CGF.EmitStoreThroughLValue(UpdateRVal, DesiredLVal);
18540b57cec5SDimitry Andric }
18550b57cec5SDimitry Andric 
18560b57cec5SDimitry Andric void AtomicInfo::EmitAtomicUpdateLibcall(llvm::AtomicOrdering AO,
18570b57cec5SDimitry Andric                                          RValue UpdateRVal, bool IsVolatile) {
18580b57cec5SDimitry Andric   auto Failure = llvm::AtomicCmpXchgInst::getStrongestFailureOrdering(AO);
18590b57cec5SDimitry Andric 
18600b57cec5SDimitry Andric   Address ExpectedAddr = CreateTempAlloca();
18610b57cec5SDimitry Andric 
1862*0fca6ea1SDimitry Andric   EmitAtomicLoadLibcall(ExpectedAddr.emitRawPointer(CGF), AO, IsVolatile);
18630b57cec5SDimitry Andric   auto *ContBB = CGF.createBasicBlock("atomic_cont");
18640b57cec5SDimitry Andric   auto *ExitBB = CGF.createBasicBlock("atomic_exit");
18650b57cec5SDimitry Andric   CGF.EmitBlock(ContBB);
18660b57cec5SDimitry Andric   Address DesiredAddr = CreateTempAlloca();
18670b57cec5SDimitry Andric   if ((LVal.isBitField() && BFI.Size != ValueSizeInBits) ||
18680b57cec5SDimitry Andric       requiresMemSetZero(getAtomicAddress().getElementType())) {
18690b57cec5SDimitry Andric     auto *OldVal = CGF.Builder.CreateLoad(ExpectedAddr);
18700b57cec5SDimitry Andric     CGF.Builder.CreateStore(OldVal, DesiredAddr);
18710b57cec5SDimitry Andric   }
18720b57cec5SDimitry Andric   EmitAtomicUpdateValue(CGF, *this, UpdateRVal, DesiredAddr);
1873*0fca6ea1SDimitry Andric   llvm::Value *ExpectedPtr = ExpectedAddr.emitRawPointer(CGF);
1874*0fca6ea1SDimitry Andric   llvm::Value *DesiredPtr = DesiredAddr.emitRawPointer(CGF);
18750b57cec5SDimitry Andric   auto *Res =
1876*0fca6ea1SDimitry Andric       EmitAtomicCompareExchangeLibcall(ExpectedPtr, DesiredPtr, AO, Failure);
18770b57cec5SDimitry Andric   CGF.Builder.CreateCondBr(Res, ExitBB, ContBB);
18780b57cec5SDimitry Andric   CGF.EmitBlock(ExitBB, /*IsFinished=*/true);
18790b57cec5SDimitry Andric }
18800b57cec5SDimitry Andric 
18810b57cec5SDimitry Andric void AtomicInfo::EmitAtomicUpdateOp(llvm::AtomicOrdering AO, RValue UpdateRVal,
18820b57cec5SDimitry Andric                                     bool IsVolatile) {
18830b57cec5SDimitry Andric   auto Failure = llvm::AtomicCmpXchgInst::getStrongestFailureOrdering(AO);
18840b57cec5SDimitry Andric 
18850b57cec5SDimitry Andric   // Do the atomic load.
1886*0fca6ea1SDimitry Andric   auto *OldVal = EmitAtomicLoadOp(Failure, IsVolatile, /*CmpXchg=*/true);
18870b57cec5SDimitry Andric   // For non-simple lvalues perform compare-and-swap procedure.
18880b57cec5SDimitry Andric   auto *ContBB = CGF.createBasicBlock("atomic_cont");
18890b57cec5SDimitry Andric   auto *ExitBB = CGF.createBasicBlock("atomic_exit");
18900b57cec5SDimitry Andric   auto *CurBB = CGF.Builder.GetInsertBlock();
18910b57cec5SDimitry Andric   CGF.EmitBlock(ContBB);
18920b57cec5SDimitry Andric   llvm::PHINode *PHI = CGF.Builder.CreatePHI(OldVal->getType(),
18930b57cec5SDimitry Andric                                              /*NumReservedValues=*/2);
18940b57cec5SDimitry Andric   PHI->addIncoming(OldVal, CurBB);
18950b57cec5SDimitry Andric   Address NewAtomicAddr = CreateTempAlloca();
189606c3fb27SDimitry Andric   Address NewAtomicIntAddr = castToAtomicIntPointer(NewAtomicAddr);
18970b57cec5SDimitry Andric   if ((LVal.isBitField() && BFI.Size != ValueSizeInBits) ||
18980b57cec5SDimitry Andric       requiresMemSetZero(getAtomicAddress().getElementType())) {
18990b57cec5SDimitry Andric     CGF.Builder.CreateStore(PHI, NewAtomicIntAddr);
19000b57cec5SDimitry Andric   }
19010b57cec5SDimitry Andric   EmitAtomicUpdateValue(CGF, *this, UpdateRVal, NewAtomicAddr);
19020b57cec5SDimitry Andric   auto *DesiredVal = CGF.Builder.CreateLoad(NewAtomicIntAddr);
19030b57cec5SDimitry Andric   // Try to write new value using cmpxchg operation.
19040b57cec5SDimitry Andric   auto Res = EmitAtomicCompareExchangeOp(PHI, DesiredVal, AO, Failure);
19050b57cec5SDimitry Andric   PHI->addIncoming(Res.first, CGF.Builder.GetInsertBlock());
19060b57cec5SDimitry Andric   CGF.Builder.CreateCondBr(Res.second, ExitBB, ContBB);
19070b57cec5SDimitry Andric   CGF.EmitBlock(ExitBB, /*IsFinished=*/true);
19080b57cec5SDimitry Andric }
19090b57cec5SDimitry Andric 
19100b57cec5SDimitry Andric void AtomicInfo::EmitAtomicUpdate(
19110b57cec5SDimitry Andric     llvm::AtomicOrdering AO, const llvm::function_ref<RValue(RValue)> &UpdateOp,
19120b57cec5SDimitry Andric     bool IsVolatile) {
19130b57cec5SDimitry Andric   if (shouldUseLibcall()) {
19140b57cec5SDimitry Andric     EmitAtomicUpdateLibcall(AO, UpdateOp, IsVolatile);
19150b57cec5SDimitry Andric   } else {
19160b57cec5SDimitry Andric     EmitAtomicUpdateOp(AO, UpdateOp, IsVolatile);
19170b57cec5SDimitry Andric   }
19180b57cec5SDimitry Andric }
19190b57cec5SDimitry Andric 
19200b57cec5SDimitry Andric void AtomicInfo::EmitAtomicUpdate(llvm::AtomicOrdering AO, RValue UpdateRVal,
19210b57cec5SDimitry Andric                                   bool IsVolatile) {
19220b57cec5SDimitry Andric   if (shouldUseLibcall()) {
19230b57cec5SDimitry Andric     EmitAtomicUpdateLibcall(AO, UpdateRVal, IsVolatile);
19240b57cec5SDimitry Andric   } else {
19250b57cec5SDimitry Andric     EmitAtomicUpdateOp(AO, UpdateRVal, IsVolatile);
19260b57cec5SDimitry Andric   }
19270b57cec5SDimitry Andric }
19280b57cec5SDimitry Andric 
19290b57cec5SDimitry Andric void CodeGenFunction::EmitAtomicStore(RValue rvalue, LValue lvalue,
19300b57cec5SDimitry Andric                                       bool isInit) {
19310b57cec5SDimitry Andric   bool IsVolatile = lvalue.isVolatileQualified();
19320b57cec5SDimitry Andric   llvm::AtomicOrdering AO;
19330b57cec5SDimitry Andric   if (lvalue.getType()->isAtomicType()) {
19340b57cec5SDimitry Andric     AO = llvm::AtomicOrdering::SequentiallyConsistent;
19350b57cec5SDimitry Andric   } else {
19360b57cec5SDimitry Andric     AO = llvm::AtomicOrdering::Release;
19370b57cec5SDimitry Andric     IsVolatile = true;
19380b57cec5SDimitry Andric   }
19390b57cec5SDimitry Andric   return EmitAtomicStore(rvalue, lvalue, AO, IsVolatile, isInit);
19400b57cec5SDimitry Andric }
19410b57cec5SDimitry Andric 
19420b57cec5SDimitry Andric /// Emit a store to an l-value of atomic type.
19430b57cec5SDimitry Andric ///
19440b57cec5SDimitry Andric /// Note that the r-value is expected to be an r-value *of the atomic
19450b57cec5SDimitry Andric /// type*; this means that for aggregate r-values, it should include
19460b57cec5SDimitry Andric /// storage for any padding that was necessary.
19470b57cec5SDimitry Andric void CodeGenFunction::EmitAtomicStore(RValue rvalue, LValue dest,
19480b57cec5SDimitry Andric                                       llvm::AtomicOrdering AO, bool IsVolatile,
19490b57cec5SDimitry Andric                                       bool isInit) {
19500b57cec5SDimitry Andric   // If this is an aggregate r-value, it should agree in type except
19510b57cec5SDimitry Andric   // maybe for address-space qualification.
19520b57cec5SDimitry Andric   assert(!rvalue.isAggregate() ||
1953480093f4SDimitry Andric          rvalue.getAggregateAddress().getElementType() ==
1954*0fca6ea1SDimitry Andric              dest.getAddress().getElementType());
19550b57cec5SDimitry Andric 
19560b57cec5SDimitry Andric   AtomicInfo atomics(*this, dest);
19570b57cec5SDimitry Andric   LValue LVal = atomics.getAtomicLValue();
19580b57cec5SDimitry Andric 
19590b57cec5SDimitry Andric   // If this is an initialization, just put the value there normally.
19600b57cec5SDimitry Andric   if (LVal.isSimple()) {
19610b57cec5SDimitry Andric     if (isInit) {
19620b57cec5SDimitry Andric       atomics.emitCopyIntoMemory(rvalue);
19630b57cec5SDimitry Andric       return;
19640b57cec5SDimitry Andric     }
19650b57cec5SDimitry Andric 
19660b57cec5SDimitry Andric     // Check whether we should use a library call.
19670b57cec5SDimitry Andric     if (atomics.shouldUseLibcall()) {
19680b57cec5SDimitry Andric       // Produce a source address.
19690b57cec5SDimitry Andric       Address srcAddr = atomics.materializeRValue(rvalue);
19700b57cec5SDimitry Andric 
19710b57cec5SDimitry Andric       // void __atomic_store(size_t size, void *mem, void *val, int order)
19720b57cec5SDimitry Andric       CallArgList args;
19730b57cec5SDimitry Andric       args.add(RValue::get(atomics.getAtomicSizeValue()),
19740b57cec5SDimitry Andric                getContext().getSizeType());
197506c3fb27SDimitry Andric       args.add(RValue::get(atomics.getAtomicPointer()), getContext().VoidPtrTy);
1976*0fca6ea1SDimitry Andric       args.add(RValue::get(srcAddr.emitRawPointer(*this)),
1977*0fca6ea1SDimitry Andric                getContext().VoidPtrTy);
19780b57cec5SDimitry Andric       args.add(
19790b57cec5SDimitry Andric           RValue::get(llvm::ConstantInt::get(IntTy, (int)llvm::toCABI(AO))),
19800b57cec5SDimitry Andric           getContext().IntTy);
19810b57cec5SDimitry Andric       emitAtomicLibcall(*this, "__atomic_store", getContext().VoidTy, args);
19820b57cec5SDimitry Andric       return;
19830b57cec5SDimitry Andric     }
19840b57cec5SDimitry Andric 
19850b57cec5SDimitry Andric     // Okay, we're doing this natively.
1986*0fca6ea1SDimitry Andric     llvm::Value *ValToStore = atomics.convertRValueToInt(rvalue);
19870b57cec5SDimitry Andric 
19880b57cec5SDimitry Andric     // Do the atomic store.
1989*0fca6ea1SDimitry Andric     Address Addr = atomics.getAtomicAddress();
1990*0fca6ea1SDimitry Andric     if (llvm::Value *Value = atomics.getScalarRValValueOrNull(rvalue))
1991*0fca6ea1SDimitry Andric       if (shouldCastToInt(Value->getType(), /*CmpXchg=*/false)) {
1992*0fca6ea1SDimitry Andric         Addr = atomics.castToAtomicIntPointer(Addr);
1993*0fca6ea1SDimitry Andric         ValToStore = Builder.CreateIntCast(ValToStore, Addr.getElementType(),
1994*0fca6ea1SDimitry Andric                                            /*isSigned=*/false);
1995*0fca6ea1SDimitry Andric       }
1996*0fca6ea1SDimitry Andric     llvm::StoreInst *store = Builder.CreateStore(ValToStore, Addr);
19970b57cec5SDimitry Andric 
19985ffd83dbSDimitry Andric     if (AO == llvm::AtomicOrdering::Acquire)
19995ffd83dbSDimitry Andric       AO = llvm::AtomicOrdering::Monotonic;
20005ffd83dbSDimitry Andric     else if (AO == llvm::AtomicOrdering::AcquireRelease)
20015ffd83dbSDimitry Andric       AO = llvm::AtomicOrdering::Release;
20020b57cec5SDimitry Andric     // Initializations don't need to be atomic.
20030b57cec5SDimitry Andric     if (!isInit)
20040b57cec5SDimitry Andric       store->setAtomic(AO);
20050b57cec5SDimitry Andric 
20060b57cec5SDimitry Andric     // Other decoration.
20070b57cec5SDimitry Andric     if (IsVolatile)
20080b57cec5SDimitry Andric       store->setVolatile(true);
20090b57cec5SDimitry Andric     CGM.DecorateInstructionWithTBAA(store, dest.getTBAAInfo());
20100b57cec5SDimitry Andric     return;
20110b57cec5SDimitry Andric   }
20120b57cec5SDimitry Andric 
20130b57cec5SDimitry Andric   // Emit simple atomic update operation.
20140b57cec5SDimitry Andric   atomics.EmitAtomicUpdate(AO, rvalue, IsVolatile);
20150b57cec5SDimitry Andric }
20160b57cec5SDimitry Andric 
20170b57cec5SDimitry Andric /// Emit a compare-and-exchange op for atomic type.
20180b57cec5SDimitry Andric ///
20190b57cec5SDimitry Andric std::pair<RValue, llvm::Value *> CodeGenFunction::EmitAtomicCompareExchange(
20200b57cec5SDimitry Andric     LValue Obj, RValue Expected, RValue Desired, SourceLocation Loc,
20210b57cec5SDimitry Andric     llvm::AtomicOrdering Success, llvm::AtomicOrdering Failure, bool IsWeak,
20220b57cec5SDimitry Andric     AggValueSlot Slot) {
20230b57cec5SDimitry Andric   // If this is an aggregate r-value, it should agree in type except
20240b57cec5SDimitry Andric   // maybe for address-space qualification.
20250b57cec5SDimitry Andric   assert(!Expected.isAggregate() ||
20260b57cec5SDimitry Andric          Expected.getAggregateAddress().getElementType() ==
2027*0fca6ea1SDimitry Andric              Obj.getAddress().getElementType());
20280b57cec5SDimitry Andric   assert(!Desired.isAggregate() ||
20290b57cec5SDimitry Andric          Desired.getAggregateAddress().getElementType() ==
2030*0fca6ea1SDimitry Andric              Obj.getAddress().getElementType());
20310b57cec5SDimitry Andric   AtomicInfo Atomics(*this, Obj);
20320b57cec5SDimitry Andric 
20330b57cec5SDimitry Andric   return Atomics.EmitAtomicCompareExchange(Expected, Desired, Success, Failure,
20340b57cec5SDimitry Andric                                            IsWeak);
20350b57cec5SDimitry Andric }
20360b57cec5SDimitry Andric 
20370b57cec5SDimitry Andric void CodeGenFunction::EmitAtomicUpdate(
20380b57cec5SDimitry Andric     LValue LVal, llvm::AtomicOrdering AO,
20390b57cec5SDimitry Andric     const llvm::function_ref<RValue(RValue)> &UpdateOp, bool IsVolatile) {
20400b57cec5SDimitry Andric   AtomicInfo Atomics(*this, LVal);
20410b57cec5SDimitry Andric   Atomics.EmitAtomicUpdate(AO, UpdateOp, IsVolatile);
20420b57cec5SDimitry Andric }
20430b57cec5SDimitry Andric 
20440b57cec5SDimitry Andric void CodeGenFunction::EmitAtomicInit(Expr *init, LValue dest) {
20450b57cec5SDimitry Andric   AtomicInfo atomics(*this, dest);
20460b57cec5SDimitry Andric 
20470b57cec5SDimitry Andric   switch (atomics.getEvaluationKind()) {
20480b57cec5SDimitry Andric   case TEK_Scalar: {
20490b57cec5SDimitry Andric     llvm::Value *value = EmitScalarExpr(init);
20500b57cec5SDimitry Andric     atomics.emitCopyIntoMemory(RValue::get(value));
20510b57cec5SDimitry Andric     return;
20520b57cec5SDimitry Andric   }
20530b57cec5SDimitry Andric 
20540b57cec5SDimitry Andric   case TEK_Complex: {
20550b57cec5SDimitry Andric     ComplexPairTy value = EmitComplexExpr(init);
20560b57cec5SDimitry Andric     atomics.emitCopyIntoMemory(RValue::getComplex(value));
20570b57cec5SDimitry Andric     return;
20580b57cec5SDimitry Andric   }
20590b57cec5SDimitry Andric 
20600b57cec5SDimitry Andric   case TEK_Aggregate: {
20610b57cec5SDimitry Andric     // Fix up the destination if the initializer isn't an expression
20620b57cec5SDimitry Andric     // of atomic type.
20630b57cec5SDimitry Andric     bool Zeroed = false;
20640b57cec5SDimitry Andric     if (!init->getType()->isAtomicType()) {
20650b57cec5SDimitry Andric       Zeroed = atomics.emitMemSetZeroIfNecessary();
20660b57cec5SDimitry Andric       dest = atomics.projectValue();
20670b57cec5SDimitry Andric     }
20680b57cec5SDimitry Andric 
20690b57cec5SDimitry Andric     // Evaluate the expression directly into the destination.
2070480093f4SDimitry Andric     AggValueSlot slot = AggValueSlot::forLValue(
2071*0fca6ea1SDimitry Andric         dest, AggValueSlot::IsNotDestructed,
2072480093f4SDimitry Andric         AggValueSlot::DoesNotNeedGCBarriers, AggValueSlot::IsNotAliased,
20730b57cec5SDimitry Andric         AggValueSlot::DoesNotOverlap,
2074480093f4SDimitry Andric         Zeroed ? AggValueSlot::IsZeroed : AggValueSlot::IsNotZeroed);
20750b57cec5SDimitry Andric 
20760b57cec5SDimitry Andric     EmitAggExpr(init, slot);
20770b57cec5SDimitry Andric     return;
20780b57cec5SDimitry Andric   }
20790b57cec5SDimitry Andric   }
20800b57cec5SDimitry Andric   llvm_unreachable("bad evaluation kind");
20810b57cec5SDimitry Andric }
2082