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