27 CharUnits atomicAlign;
30 bool useLibCall =
true;
35 AtomicInfo(CIRGenFunction &cgf, LValue &lvalue, mlir::Location loc)
36 : cgf(cgf), loc(loc) {
37 assert(!lvalue.isGlobalReg());
38 ASTContext &ctx = cgf.getContext();
39 if (lvalue.isSimple()) {
40 atomicTy = lvalue.getType();
41 if (
auto *ty = atomicTy->getAs<AtomicType>())
42 valueTy = ty->getValueType();
45 evaluationKind = cgf.getEvaluationKind(valueTy);
48 TypeInfo atomicTypeInfo = ctx.
getTypeInfo(atomicTy);
51 valueSizeInBits = valueTypeInfo.
Width;
52 atomicSizeInBits = atomicTypeInfo.
Width;
53 assert(valueSizeInBits <= atomicSizeInBits);
54 assert(valueAlignInBits <= atomicAlignInBits);
58 if (lvalue.getAlignment().isZero())
59 lvalue.setAlignment(atomicAlign);
61 this->lvalue = lvalue;
64 cgf.cgm.errorNYI(loc,
"AtomicInfo: non-simple lvalue");
67 atomicSizeInBits, ctx.
toBits(lvalue.getAlignment()));
70 QualType getValueType()
const {
return valueTy; }
71 QualType getAtomicType()
const {
return atomicTy; }
72 CharUnits getAtomicAlignment()
const {
return atomicAlign; }
74 mlir::Value getAtomicPointer()
const {
75 if (lvalue.isSimple())
76 return lvalue.getPointer();
80 bool shouldUseLibCall()
const {
return useLibCall; }
81 const LValue &getAtomicLValue()
const {
return lvalue; }
82 Address getAtomicAddress()
const {
84 if (lvalue.isSimple()) {
85 elemTy = lvalue.getAddress().getElementType();
88 cgf.cgm.errorNYI(loc,
"AtomicInfo::getAtomicAddress: non-simple lvalue");
90 return Address(getAtomicPointer(), elemTy, getAtomicAlignment());
99 bool hasPadding()
const {
return (valueSizeInBits != atomicSizeInBits); }
101 bool emitMemSetZeroIfNecessary()
const;
103 mlir::Value getScalarRValValueOrNull(RValue rvalue)
const;
107 Address castToAtomicIntPointer(Address addr)
const;
112 Address convertToAtomicIntPointer(Address addr, mlir::Location loc)
const;
115 RValue convertAtomicTempToRValue(Address addr, AggValueSlot resultSlot,
116 SourceLocation loc,
bool asValue)
const;
119 mlir::Value convertRValueToInt(RValue rvalue, mlir::Location loc,
120 bool cmpxchg =
false)
const;
122 RValue convertToValueOrAtomic(mlir::Value intVal, AggValueSlot resultSlot,
123 SourceLocation loc,
bool asValue,
124 bool cmpxchg =
false)
const;
127 void emitCopyIntoMemory(RValue rvalue)
const;
130 LValue projectValue()
const {
131 assert(lvalue.isSimple());
132 Address addr = getAtomicAddress();
134 addr = cgf.getBuilder().createGetMember(loc, addr,
"value",
136 cgf.cgm.getDataLayout());
139 return LValue::makeAddr(addr, getValueType(), lvalue.getBaseInfo());
144 RValue emitAtomicLoad(AggValueSlot resultSlot, SourceLocation loc,
145 bool asValue, cir::MemOrder order,
bool isVolatile);
148 Address materializeRValue(RValue rvalue, mlir::Location loc)
const;
151 Address createTempAlloca()
const;
154 bool requiresMemSetZero(mlir::Type ty)
const;
157 mlir::Value emitAtomicLoadOp(cir::MemOrder order,
bool isVolatile,
158 bool cmpxchg =
false);
175 mlir::UnitAttr unit = cgf.
getBuilder().getUnitAttr();
176 if (
expr->threadPrivateMemoryAtomicsAreUndefined())
177 op->setAttr(cir::CIRDialect::getAMDGPUNoPrivateAddrSpaceAttrName(), unit);
181 auto fetchOp = mlir::dyn_cast<cir::AtomicFetchOp>(op);
187 op->setAttr(cir::CIRDialect::getAMDGPUNoFineGrainedMemoryAttrName(), unit);
189 op->setAttr(cir::CIRDialect::getAMDGPUNoRemoteMemoryAttrName(), unit);
192 fetchOp.getBinop() == cir::AtomicFetchKind::Add &&
193 mlir::isa<cir::SingleType>(fetchOp.getVal().getType()))
194 op->setAttr(cir::CIRDialect::getAMDGPUIgnoreDenormalModeAttrName(), unit);
209 uint64_t expectedSize) {
216bool AtomicInfo::requiresMemSetZero(mlir::Type ty)
const {
222 switch (getEvaluationKind()) {
229 mlir::cast<cir::ComplexType>(ty).getElementType(),
230 atomicSizeInBits / 2);
235 llvm_unreachable(
"bad evaluation kind");
238Address AtomicInfo::convertToAtomicIntPointer(Address addr,
239 mlir::Location loc)
const {
242 if (sourceSizeInBits != atomicSizeInBits) {
245 Address tmp = createTempAlloca();
257 std::min(atomicSizeInBits, sourceSizeInBits) / 8));
261 return castToAtomicIntPointer(addr);
264RValue AtomicInfo::convertAtomicTempToRValue(Address addr,
265 AggValueSlot resultSlot,
267 bool asValue)
const {
268 if (lvalue.isSimple()) {
275 "AtomicInfo::convertAtomicTempToRValue: hasPadding");
285 loc,
"AtomicInfo::convertAtomicTempToRValue: lvalue is not simple");
289RValue AtomicInfo::emitAtomicLoad(AggValueSlot resultSlot, SourceLocation loc,
290 bool asValue, cir::MemOrder order,
293 if (shouldUseLibCall()) {
295 cgf.
cgm.
errorNYI(loc,
"emitAtomicLoad: emit atomic lib call");
300 mlir::Value loadOp = emitAtomicLoadOp(order, isVolatile);
308 return convertToValueOrAtomic(loadOp, resultSlot, loc, asValue);
311Address AtomicInfo::createTempAlloca()
const {
314 QualType tmpTy = (lvalue.isBitField() && valueSizeInBits > atomicSizeInBits)
318 cgf.
createMemTemp(tmpTy, getAtomicAlignment(), loc,
"atomic-temp");
321 if (lvalue.isBitField()) {
322 cgf.
cgm.
errorNYI(loc,
"AtomicInfo::createTempAlloca: bitfield lvalue");
328mlir::Value AtomicInfo::getScalarRValValueOrNull(RValue rvalue)
const {
329 if (rvalue.
isScalar() && (!hasPadding() || !lvalue.isSimple()))
334Address AtomicInfo::castToAtomicIntPointer(Address addr)
const {
337 if (intTy && intTy.getWidth() == atomicSizeInBits)
343bool AtomicInfo::emitMemSetZeroIfNecessary()
const {
344 assert(lvalue.isSimple());
345 Address addr = lvalue.getAddress();
365 if (cir::isAnyFloatingPointType(valueTy))
370mlir::Value AtomicInfo::emitAtomicLoadOp(cir::MemOrder order,
bool isVolatile,
372 Address addr = getAtomicAddress();
374 addr = castToAtomicIntPointer(addr);
378 op.setMemOrder(order);
384mlir::Value AtomicInfo::convertRValueToInt(RValue rvalue, mlir::Location loc,
385 bool cmpxchg)
const {
388 if (mlir::Value value = getScalarRValValueOrNull(rvalue)) {
393 loc,
"AtomicInfo::convertRValueToInt: cast scalar rvalue to int");
399 Address addr = materializeRValue(rvalue, loc);
402 addr = castToAtomicIntPointer(addr);
407RValue AtomicInfo::convertToValueOrAtomic(mlir::Value intVal,
408 AggValueSlot resultSlot,
409 SourceLocation loc,
bool asValue,
410 bool cmpxchg)
const {
412 assert((mlir::isa<cir::IntType, cir::PointerType, cir::FPTypeInterface>(
413 intVal.getType())) &&
414 "Expected integer, pointer or floating point value when converting "
417 !lvalue.isBitField() || lvalue.getBitFieldInfo().size == valueSizeInBits;
419 ((isWholeValue && !hasPadding()) || !asValue)) {
421 : getAtomicAddress().getElementType();
423 assert((!mlir::isa<cir::IntType>(valTy) || intVal.getType() == valTy) &&
424 "Different integer types.");
428 cgf.
cgm.
errorNYI(
"convertToValueOrAtomic: convert through bitcast");
435 bool tempIsVolatile =
false;
441 temp = createTempAlloca();
445 Address castTemp = castToAtomicIntPointer(temp);
448 return convertAtomicTempToRValue(temp, resultSlot, loc, asValue);
453void AtomicInfo::emitCopyIntoMemory(RValue rvalue)
const {
454 assert(lvalue.isSimple());
460 cgf.
cgm.
errorNYI(
"copying aggregate into atomic lvalue");
467 emitMemSetZeroIfNecessary();
470 LValue tempLValue = projectValue();
483Address AtomicInfo::materializeRValue(RValue rvalue, mlir::Location loc)
const {
490 LValue tempLV = cgf.
makeAddrLValue(createTempAlloca(), getAtomicType());
491 AtomicInfo atomics(cgf, tempLV, loc);
493 atomics.emitCopyIntoMemory(rvalue);
494 return tempLV.getAddress();
498 mlir::ArrayAttr valuesAttr = builder.getArrayAttr({});
499 mlir::OpBuilder::InsertPoint insertPoint;
500 cir::CaseOp::create(builder, loc, valuesAttr, cir::CaseOpKind::Default,
502 builder.restoreInsertionPoint(insertPoint);
508 mlir::Type orderType,
511 for (cir::MemOrder order : orders)
512 orderAttrs.push_back(cir::IntAttr::get(orderType,
static_cast<int>(order)));
513 mlir::ArrayAttr ordersAttr = builder.getArrayAttr(orderAttrs);
515 mlir::OpBuilder::InsertPoint insertPoint;
516 cir::CaseOp::create(builder, loc, ordersAttr, cir::CaseOpKind::Anyof,
518 builder.restoreInsertionPoint(insertPoint);
524 uint64_t size, cir::MemOrder successOrder,
525 cir::MemOrder failureOrder,
526 cir::SyncScopeKind scope) {
530 mlir::Value expected = builder.
createLoad(loc, val1);
531 mlir::Value desired = builder.
createLoad(loc, val2);
533 auto cmpxchg = cir::AtomicCmpXchgOp::create(
542 cmpxchg.setWeak(isWeak);
546 mlir::Value failed = builder.
createNot(cmpxchg.getSuccess());
548 builder, loc, failed,
false,
549 [&](mlir::OpBuilder &, mlir::Location) {
553 if (expectedSizeInBytes == size) {
555 builder, cmpxchg.getOld().getType());
556 builder.
createStore(loc, cmpxchg.getOld(), storeAddr);
560 cmpxchg.getOld().getType(), ptr.
getAlignment(), loc,
"old.tmp");
561 builder.
createStore(loc, cmpxchg.getOld(), oldTmp);
568 loc, expectedVoid, oldTmpVoid,
583 uint64_t size, cir::MemOrder successOrder, cir::SyncScopeKind scope) {
586 uint64_t failureOrderInt = failureOrderEval.
Val.
getInt().getZExtValue();
588 cir::MemOrder failureOrder;
590 failureOrder = cir::MemOrder::Relaxed;
592 switch ((cir::MemOrder)failureOrderInt) {
593 case cir::MemOrder::Relaxed:
596 case cir::MemOrder::Release:
597 case cir::MemOrder::AcquireRelease:
598 failureOrder = cir::MemOrder::Relaxed;
600 case cir::MemOrder::Consume:
601 case cir::MemOrder::Acquire:
602 failureOrder = cir::MemOrder::Acquire;
604 case cir::MemOrder::SequentiallyConsistent:
605 failureOrder = cir::MemOrder::SequentiallyConsistent;
615 size, successOrder, failureOrder, scope);
623 mlir::Value failureOrderVal = cgf.
emitScalarExpr(failureOrderExpr);
625 cir::SwitchOp::create(
627 [&](mlir::OpBuilder &b, mlir::Location loc, mlir::OperationState &os) {
628 mlir::Block *switchBlock = cgf.getBuilder().getBlock();
640 emitDefaultCaseLabel(cgf.getBuilder(), atomicLoc);
641 emitAtomicCmpXchg(cgf, e, isWeak, dest, ptr, val1, val2, expectedResult,
642 size, successOrder, cir::MemOrder::Relaxed, scope);
643 cgf.getBuilder().createBreak(atomicLoc);
644 cgf.getBuilder().setInsertionPointToEnd(switchBlock);
648 emitMemOrderCaseLabel(cgf.getBuilder(), loc, failureOrderVal.getType(),
649 {cir::MemOrder::Consume, cir::MemOrder::Acquire});
651 size, successOrder, cir::MemOrder::Acquire, scope);
653 cgf.
getBuilder().setInsertionPointToEnd(switchBlock);
657 {cir::MemOrder::SequentiallyConsistent});
660 cir::MemOrder::SequentiallyConsistent, scope);
662 cgf.
getBuilder().setInsertionPointToEnd(switchBlock);
674 Expr *failureOrderExpr, uint64_t size, cir::MemOrder successOrder,
675 cir::SyncScopeKind scope) {
687 [&](mlir::OpBuilder &b, mlir::Location loc) {
688 emitAtomicCmpXchgFailureSet(cgf, e, true, dest, ptr, val1,
689 val2, expectedResult, failureOrderExpr,
690 size, successOrder, scope);
691 cgf.getBuilder().createYield(atomicLoc);
693 [&](mlir::OpBuilder &b, mlir::Location loc) {
694 emitAtomicCmpXchgFailureSet(cgf, e, false, dest, ptr, val1,
695 val2, expectedResult, failureOrderExpr,
696 size, successOrder, scope);
697 cgf.getBuilder().createYield(atomicLoc);
704 Expr *failureOrderExpr, int64_t size,
705 cir::MemOrder order, cir::SyncScopeKind scope) {
707 llvm::StringRef opName;
710 mlir::Location loc = cgf.
getLoc(
expr->getSourceRange());
711 auto orderAttr = cir::MemOrderAttr::get(builder.getContext(), order);
712 auto scopeAttr = cir::SyncScopeKindAttr::get(builder.getContext(), scope);
713 cir::AtomicFetchKindAttr fetchAttr;
714 bool fetchFirst =
true;
716 auto handleFetchOp = [&](cir::AtomicFetchKind
kind) {
717 opName = cir::AtomicFetchOp::getOperationName();
718 fetchAttr = cir::AtomicFetchKindAttr::get(builder.getContext(),
kind);
721 switch (
expr->getOp()) {
722 case AtomicExpr::AO__c11_atomic_init:
723 llvm_unreachable(
"already handled!");
725 case AtomicExpr::AO__c11_atomic_compare_exchange_strong:
726 case AtomicExpr::AO__hip_atomic_compare_exchange_strong:
727 case AtomicExpr::AO__opencl_atomic_compare_exchange_strong:
729 val2, expectedResult, failureOrderExpr, size,
733 case AtomicExpr::AO__c11_atomic_compare_exchange_weak:
734 case AtomicExpr::AO__hip_atomic_compare_exchange_weak:
735 case AtomicExpr::AO__opencl_atomic_compare_exchange_weak:
737 val2, expectedResult, failureOrderExpr, size,
741 case AtomicExpr::AO__atomic_compare_exchange:
742 case AtomicExpr::AO__atomic_compare_exchange_n:
743 case AtomicExpr::AO__scoped_atomic_compare_exchange:
744 case AtomicExpr::AO__scoped_atomic_compare_exchange_n: {
748 expectedResult, failureOrderExpr, size, order,
752 cgf,
expr, isWeakExpr, dest, ptr, val1, val2, expectedResult,
753 failureOrderExpr, size, order, scope);
758 case AtomicExpr::AO__c11_atomic_load:
759 case AtomicExpr::AO__atomic_load_n:
760 case AtomicExpr::AO__atomic_load:
761 case AtomicExpr::AO__scoped_atomic_load_n:
762 case AtomicExpr::AO__scoped_atomic_load:
763 case AtomicExpr::AO__hip_atomic_load:
764 case AtomicExpr::AO__opencl_atomic_load: {
768 load->setAttr(
"mem_order", orderAttr);
769 load->setAttr(
"sync_scope", scopeAttr);
771 builder.
createStore(loc, load->getResult(0), dest);
775 case AtomicExpr::AO__c11_atomic_store:
776 case AtomicExpr::AO__atomic_store_n:
777 case AtomicExpr::AO__atomic_store:
778 case AtomicExpr::AO__scoped_atomic_store:
779 case AtomicExpr::AO__scoped_atomic_store_n:
780 case AtomicExpr::AO__hip_atomic_store:
781 case AtomicExpr::AO__opencl_atomic_store: {
782 cir::LoadOp loadVal1 = builder.
createLoad(loc, val1);
788 mlir::IntegerAttr{}, scopeAttr, orderAttr);
792 case AtomicExpr::AO__c11_atomic_exchange:
793 case AtomicExpr::AO__atomic_exchange_n:
794 case AtomicExpr::AO__atomic_exchange:
795 case AtomicExpr::AO__scoped_atomic_exchange_n:
796 case AtomicExpr::AO__scoped_atomic_exchange:
797 case AtomicExpr::AO__hip_atomic_exchange:
798 case AtomicExpr::AO__opencl_atomic_exchange:
799 opName = cir::AtomicXchgOp::getOperationName();
802 case AtomicExpr::AO__atomic_add_fetch:
803 case AtomicExpr::AO__scoped_atomic_add_fetch:
806 case AtomicExpr::AO__c11_atomic_fetch_add:
807 case AtomicExpr::AO__atomic_fetch_add:
808 case AtomicExpr::AO__scoped_atomic_fetch_add:
809 case AtomicExpr::AO__hip_atomic_fetch_add:
810 case AtomicExpr::AO__opencl_atomic_fetch_add:
811 handleFetchOp(cir::AtomicFetchKind::Add);
814 case AtomicExpr::AO__atomic_sub_fetch:
815 case AtomicExpr::AO__scoped_atomic_sub_fetch:
818 case AtomicExpr::AO__c11_atomic_fetch_sub:
819 case AtomicExpr::AO__atomic_fetch_sub:
820 case AtomicExpr::AO__scoped_atomic_fetch_sub:
821 case AtomicExpr::AO__hip_atomic_fetch_sub:
822 case AtomicExpr::AO__opencl_atomic_fetch_sub:
823 handleFetchOp(cir::AtomicFetchKind::Sub);
826 case AtomicExpr::AO__atomic_min_fetch:
827 case AtomicExpr::AO__scoped_atomic_min_fetch:
830 case AtomicExpr::AO__c11_atomic_fetch_min:
831 case AtomicExpr::AO__atomic_fetch_min:
832 case AtomicExpr::AO__scoped_atomic_fetch_min:
833 case AtomicExpr::AO__hip_atomic_fetch_min:
834 case AtomicExpr::AO__opencl_atomic_fetch_min:
835 handleFetchOp(cir::AtomicFetchKind::Min);
838 case AtomicExpr::AO__atomic_fetch_fminimum:
839 case AtomicExpr::AO__scoped_atomic_fetch_fminimum:
840 assert(
expr->getValueType()->isFloatingType() &&
841 "fminimum operations only support floating-point types");
842 handleFetchOp(cir::AtomicFetchKind::Minimum);
845 case AtomicExpr::AO__atomic_fetch_fminimum_num:
846 case AtomicExpr::AO__scoped_atomic_fetch_fminimum_num:
847 assert(
expr->getValueType()->isFloatingType() &&
848 "fminimum_num operations only support floating-point types");
849 handleFetchOp(cir::AtomicFetchKind::MinimumNum);
852 case AtomicExpr::AO__atomic_max_fetch:
853 case AtomicExpr::AO__scoped_atomic_max_fetch:
856 case AtomicExpr::AO__c11_atomic_fetch_max:
857 case AtomicExpr::AO__atomic_fetch_max:
858 case AtomicExpr::AO__scoped_atomic_fetch_max:
859 case AtomicExpr::AO__hip_atomic_fetch_max:
860 case AtomicExpr::AO__opencl_atomic_fetch_max:
861 handleFetchOp(cir::AtomicFetchKind::Max);
864 case AtomicExpr::AO__atomic_fetch_fmaximum:
865 case AtomicExpr::AO__scoped_atomic_fetch_fmaximum:
866 assert(
expr->getValueType()->isFloatingType() &&
867 "fmaximum operations only support floating-point types");
868 handleFetchOp(cir::AtomicFetchKind::Maximum);
871 case AtomicExpr::AO__atomic_fetch_fmaximum_num:
872 case AtomicExpr::AO__scoped_atomic_fetch_fmaximum_num:
873 assert(
expr->getValueType()->isFloatingType() &&
874 "fmaximum_num operations only support floating-point types");
875 handleFetchOp(cir::AtomicFetchKind::MaximumNum);
878 case AtomicExpr::AO__atomic_and_fetch:
879 case AtomicExpr::AO__scoped_atomic_and_fetch:
882 case AtomicExpr::AO__c11_atomic_fetch_and:
883 case AtomicExpr::AO__atomic_fetch_and:
884 case AtomicExpr::AO__scoped_atomic_fetch_and:
885 case AtomicExpr::AO__hip_atomic_fetch_and:
886 case AtomicExpr::AO__opencl_atomic_fetch_and:
887 handleFetchOp(cir::AtomicFetchKind::And);
890 case AtomicExpr::AO__atomic_or_fetch:
891 case AtomicExpr::AO__scoped_atomic_or_fetch:
894 case AtomicExpr::AO__c11_atomic_fetch_or:
895 case AtomicExpr::AO__atomic_fetch_or:
896 case AtomicExpr::AO__scoped_atomic_fetch_or:
897 case AtomicExpr::AO__hip_atomic_fetch_or:
898 case AtomicExpr::AO__opencl_atomic_fetch_or:
899 handleFetchOp(cir::AtomicFetchKind::Or);
902 case AtomicExpr::AO__atomic_xor_fetch:
903 case AtomicExpr::AO__scoped_atomic_xor_fetch:
906 case AtomicExpr::AO__c11_atomic_fetch_xor:
907 case AtomicExpr::AO__atomic_fetch_xor:
908 case AtomicExpr::AO__scoped_atomic_fetch_xor:
909 case AtomicExpr::AO__hip_atomic_fetch_xor:
910 case AtomicExpr::AO__opencl_atomic_fetch_xor:
911 handleFetchOp(cir::AtomicFetchKind::Xor);
914 case AtomicExpr::AO__atomic_nand_fetch:
915 case AtomicExpr::AO__scoped_atomic_nand_fetch:
918 case AtomicExpr::AO__c11_atomic_fetch_nand:
919 case AtomicExpr::AO__atomic_fetch_nand:
920 case AtomicExpr::AO__scoped_atomic_fetch_nand:
921 handleFetchOp(cir::AtomicFetchKind::Nand);
924 case AtomicExpr::AO__atomic_test_and_set: {
925 auto op = cir::AtomicTestAndSetOp::create(
933 case AtomicExpr::AO__atomic_clear: {
934 cir::AtomicClearOp::create(
941 case AtomicExpr::AO__atomic_fetch_uinc:
942 case AtomicExpr::AO__scoped_atomic_fetch_uinc:
943 handleFetchOp(cir::AtomicFetchKind::UIncWrap);
946 case AtomicExpr::AO__atomic_fetch_udec:
947 case AtomicExpr::AO__scoped_atomic_fetch_udec:
948 handleFetchOp(cir::AtomicFetchKind::UDecWrap);
951 case AtomicExpr::AO__opencl_atomic_init:
956 assert(!opName.empty() &&
"expected operation name to build");
957 mlir::Value loadVal1 = builder.
createLoad(loc, val1);
961 mlir::Operation *rmwOp = builder.create(loc, builder.getStringAttr(opName),
962 atomicOperands, atomicResTys);
965 rmwOp->setAttr(
"binop", fetchAttr);
966 rmwOp->setAttr(
"mem_order", orderAttr);
967 rmwOp->setAttr(
"sync_scope", scopeAttr);
968 if (
expr->isVolatile())
969 rmwOp->setAttr(
"is_volatile", builder.getUnitAttr());
970 if (fetchFirst && opName == cir::AtomicFetchOp::getOperationName())
971 rmwOp->setAttr(
"fetch_first", builder.getUnitAttr());
976 mlir::Value result = rmwOp->getResult(0);
987 return cir::SyncScopeKind::SingleThread;
989 return cir::SyncScopeKind::System;
991 return cir::SyncScopeKind::Device;
993 return cir::SyncScopeKind::Workgroup;
995 return cir::SyncScopeKind::Wavefront;
997 return cir::SyncScopeKind::Cluster;
1000 return cir::SyncScopeKind::HIPSingleThread;
1002 return cir::SyncScopeKind::HIPSystem;
1004 return cir::SyncScopeKind::HIPAgent;
1006 return cir::SyncScopeKind::HIPWorkgroup;
1008 return cir::SyncScopeKind::HIPWavefront;
1010 return cir::SyncScopeKind::HIPCluster;
1013 return cir::SyncScopeKind::OpenCLWorkGroup;
1015 return cir::SyncScopeKind::OpenCLDevice;
1017 return cir::SyncScopeKind::OpenCLAllSVMDevices;
1019 return cir::SyncScopeKind::OpenCLSubGroup;
1022 llvm_unreachable(
"unhandled sync scope");
1028 Expr *failureOrderExpr, int64_t size,
1029 cir::MemOrder order,
1030 const std::optional<Expr::EvalResult> &scopeConst,
1031 mlir::Value scopeValue) {
1032 std::unique_ptr<AtomicScopeModel> scopeModel =
expr->getScopeModel();
1036 failureOrderExpr, size, order, cir::SyncScopeKind::System);
1040 if (scopeConst.has_value()) {
1042 cgf,
expr->getScope()->getSourceRange(),
1043 scopeModel->map(scopeConst->Val.getInt().getZExtValue()));
1045 failureOrderExpr, size, order, mappedScope);
1052 mlir::Location loc = cgf.
getLoc(
expr->getSourceRange());
1054 unsigned fallback = scopeModel->getFallBackValue();
1056 cir::SwitchOp::create(
1057 builder, loc, scopeValue,
1058 [&](mlir::OpBuilder &, mlir::Location loc, mlir::OperationState &) {
1059 mlir::Block *switchBlock = builder.getBlock();
1063 cgf,
expr->getScope()->getSourceRange(), scopeModel->map(fallback));
1066 isWeakExpr, failureOrderExpr, size, order, fallbackScope);
1068 builder.setInsertionPointToEnd(switchBlock);
1071 for (
unsigned scope : allScopes) {
1072 if (scope == fallback)
1076 cgf,
expr->getScope()->getSourceRange(), scopeModel->map(scope));
1078 mlir::ArrayAttr casesAttr = builder.getArrayAttr(
1079 {cir::IntAttr::get(scopeValue.getType(), scope)});
1080 mlir::OpBuilder::InsertPoint insertPoint;
1081 cir::CaseOp::create(builder, loc, casesAttr, cir::CaseOpKind::Equal,
1084 builder.restoreInsertionPoint(insertPoint);
1086 isWeakExpr, failureOrderExpr, size, order, cirScope);
1088 builder.setInsertionPointToEnd(switchBlock);
1095static std::optional<cir::MemOrder>
1105 if (oriOrder == cir::MemOrder::Consume ||
1106 oriOrder == cir::MemOrder::Acquire ||
1107 oriOrder == cir::MemOrder::AcquireRelease)
1108 return std::nullopt;
1109 }
else if (isLoad) {
1110 if (oriOrder == cir::MemOrder::Release ||
1111 oriOrder == cir::MemOrder::AcquireRelease)
1112 return std::nullopt;
1113 }
else if (isFence) {
1114 if (oriOrder == cir::MemOrder::Relaxed)
1115 return std::nullopt;
1119 if (oriOrder == cir::MemOrder::Consume)
1120 return cir::MemOrder::Acquire;
1125 CIRGenFunction &cgf, mlir::Value order,
bool isStore,
bool isLoad,
1126 bool isFence, llvm::function_ref<
void(cir::MemOrder)> emitAtomicOpFn) {
1134 cir::SwitchOp::create(
1135 builder, order.getLoc(), order,
1136 [&](mlir::OpBuilder &, mlir::Location loc, mlir::OperationState &) {
1137 mlir::Block *switchBlock = builder.getBlock();
1139 auto emitMemOrderCase = [&](llvm::ArrayRef<cir::MemOrder> caseOrders) {
1141 for (int i = 1, e = caseOrders.size(); i < e; i++)
1142 assert((getEffectiveAtomicMemOrder(caseOrders[i - 1], isStore,
1144 getEffectiveAtomicMemOrder(caseOrders[i], isStore, isLoad,
1146 "Effective memory order must be same!");
1148 if (caseOrders.empty()) {
1149 emitDefaultCaseLabel(builder, loc);
1153 emitAtomicOpFn(cir::MemOrder::Relaxed);
1154 } else if (std::optional<cir::MemOrder> actualOrder =
1155 getEffectiveAtomicMemOrder(caseOrders[0], isStore,
1158 if (!isFence && actualOrder == cir::MemOrder::Relaxed)
1163 emitMemOrderCaseLabel(builder, loc, order.getType(), caseOrders);
1164 emitAtomicOpFn(actualOrder.value());
1169 builder.createBreak(loc);
1170 builder.setInsertionPointToEnd(switchBlock);
1173 emitMemOrderCase( {});
1174 emitMemOrderCase({cir::MemOrder::Relaxed});
1175 emitMemOrderCase({cir::MemOrder::Consume, cir::MemOrder::Acquire});
1176 emitMemOrderCase({cir::MemOrder::Release});
1177 emitMemOrderCase({cir::MemOrder::AcquireRelease});
1178 emitMemOrderCase({cir::MemOrder::SequentiallyConsistent});
1185 const Expr *memOrder,
bool isStore,
bool isLoad,
bool isFence,
1186 llvm::function_ref<
void(cir::MemOrder)> emitAtomicOpFn) {
1190 uint64_t constOrder = eval.
Val.
getInt().getZExtValue();
1195 cir::MemOrder oriOrder =
static_cast<cir::MemOrder
>(constOrder);
1196 if (std::optional<cir::MemOrder> actualOrder =
1198 emitAtomicOpFn(actualOrder.value());
1215 mlir::NamedAttrList fnAttrs;
1227 uint64_t atomicTySize,
1240 auto castToGenericAddrSpace = [&](mlir::Value v,
QualType pt) {
1245 cgf.
cgm.
errorNYI(loc,
"emitLibCallForAtomicExpr: openCL");
1255 llvm::StringRef calleeName;
1257 bool hasRetTy =
false;
1258 switch (e->
getOp()) {
1259 case AtomicExpr::AO__c11_atomic_init:
1260 case AtomicExpr::AO__opencl_atomic_init:
1261 llvm_unreachable(
"Already handled!");
1268 case AtomicExpr::AO__atomic_compare_exchange:
1269 case AtomicExpr::AO__atomic_compare_exchange_n:
1270 case AtomicExpr::AO__c11_atomic_compare_exchange_weak:
1271 case AtomicExpr::AO__c11_atomic_compare_exchange_strong:
1272 case AtomicExpr::AO__hip_atomic_compare_exchange_weak:
1273 case AtomicExpr::AO__hip_atomic_compare_exchange_strong:
1274 case AtomicExpr::AO__opencl_atomic_compare_exchange_weak:
1275 case AtomicExpr::AO__opencl_atomic_compare_exchange_strong:
1276 case AtomicExpr::AO__scoped_atomic_compare_exchange:
1277 case AtomicExpr::AO__scoped_atomic_compare_exchange_n: {
1278 calleeName =
"__atomic_compare_exchange";
1295 case AtomicExpr::AO__atomic_exchange:
1296 case AtomicExpr::AO__atomic_exchange_n:
1297 case AtomicExpr::AO__c11_atomic_exchange:
1298 case AtomicExpr::AO__hip_atomic_exchange:
1299 case AtomicExpr::AO__opencl_atomic_exchange:
1300 case AtomicExpr::AO__scoped_atomic_exchange:
1301 case AtomicExpr::AO__scoped_atomic_exchange_n:
1302 calleeName =
"__atomic_exchange";
1309 case AtomicExpr::AO__atomic_store:
1310 case AtomicExpr::AO__atomic_store_n:
1311 case AtomicExpr::AO__c11_atomic_store:
1312 case AtomicExpr::AO__hip_atomic_store:
1313 case AtomicExpr::AO__opencl_atomic_store:
1314 case AtomicExpr::AO__scoped_atomic_store:
1315 case AtomicExpr::AO__scoped_atomic_store_n:
1316 calleeName =
"__atomic_store";
1325 case AtomicExpr::AO__atomic_load:
1326 case AtomicExpr::AO__atomic_load_n:
1327 case AtomicExpr::AO__c11_atomic_load:
1328 case AtomicExpr::AO__hip_atomic_load:
1329 case AtomicExpr::AO__opencl_atomic_load:
1330 case AtomicExpr::AO__scoped_atomic_load:
1331 case AtomicExpr::AO__scoped_atomic_load_n:
1332 calleeName =
"__atomic_load";
1335 case AtomicExpr::AO__atomic_add_fetch:
1336 case AtomicExpr::AO__scoped_atomic_add_fetch:
1337 case AtomicExpr::AO__atomic_fetch_add:
1338 case AtomicExpr::AO__c11_atomic_fetch_add:
1339 case AtomicExpr::AO__hip_atomic_fetch_add:
1340 case AtomicExpr::AO__opencl_atomic_fetch_add:
1341 case AtomicExpr::AO__scoped_atomic_fetch_add:
1342 case AtomicExpr::AO__atomic_and_fetch:
1343 case AtomicExpr::AO__scoped_atomic_and_fetch:
1344 case AtomicExpr::AO__atomic_fetch_and:
1345 case AtomicExpr::AO__c11_atomic_fetch_and:
1346 case AtomicExpr::AO__hip_atomic_fetch_and:
1347 case AtomicExpr::AO__opencl_atomic_fetch_and:
1348 case AtomicExpr::AO__scoped_atomic_fetch_and:
1349 case AtomicExpr::AO__atomic_or_fetch:
1350 case AtomicExpr::AO__scoped_atomic_or_fetch:
1351 case AtomicExpr::AO__atomic_fetch_or:
1352 case AtomicExpr::AO__c11_atomic_fetch_or:
1353 case AtomicExpr::AO__hip_atomic_fetch_or:
1354 case AtomicExpr::AO__opencl_atomic_fetch_or:
1355 case AtomicExpr::AO__scoped_atomic_fetch_or:
1356 case AtomicExpr::AO__atomic_sub_fetch:
1357 case AtomicExpr::AO__scoped_atomic_sub_fetch:
1358 case AtomicExpr::AO__atomic_fetch_sub:
1359 case AtomicExpr::AO__c11_atomic_fetch_sub:
1360 case AtomicExpr::AO__hip_atomic_fetch_sub:
1361 case AtomicExpr::AO__opencl_atomic_fetch_sub:
1362 case AtomicExpr::AO__scoped_atomic_fetch_sub:
1363 case AtomicExpr::AO__atomic_xor_fetch:
1364 case AtomicExpr::AO__scoped_atomic_xor_fetch:
1365 case AtomicExpr::AO__atomic_fetch_xor:
1366 case AtomicExpr::AO__c11_atomic_fetch_xor:
1367 case AtomicExpr::AO__hip_atomic_fetch_xor:
1368 case AtomicExpr::AO__opencl_atomic_fetch_xor:
1369 case AtomicExpr::AO__scoped_atomic_fetch_xor:
1370 case AtomicExpr::AO__atomic_nand_fetch:
1371 case AtomicExpr::AO__atomic_fetch_nand:
1372 case AtomicExpr::AO__c11_atomic_fetch_nand:
1373 case AtomicExpr::AO__scoped_atomic_fetch_nand:
1374 case AtomicExpr::AO__scoped_atomic_nand_fetch:
1375 case AtomicExpr::AO__atomic_min_fetch:
1376 case AtomicExpr::AO__atomic_fetch_min:
1377 case AtomicExpr::AO__c11_atomic_fetch_min:
1378 case AtomicExpr::AO__hip_atomic_fetch_min:
1379 case AtomicExpr::AO__opencl_atomic_fetch_min:
1380 case AtomicExpr::AO__scoped_atomic_fetch_min:
1381 case AtomicExpr::AO__scoped_atomic_min_fetch:
1382 case AtomicExpr::AO__atomic_max_fetch:
1383 case AtomicExpr::AO__atomic_fetch_max:
1384 case AtomicExpr::AO__c11_atomic_fetch_max:
1385 case AtomicExpr::AO__hip_atomic_fetch_max:
1386 case AtomicExpr::AO__opencl_atomic_fetch_max:
1387 case AtomicExpr::AO__scoped_atomic_fetch_max:
1388 case AtomicExpr::AO__scoped_atomic_max_fetch:
1389 case AtomicExpr::AO__scoped_atomic_fetch_uinc:
1390 case AtomicExpr::AO__scoped_atomic_fetch_udec:
1391 case AtomicExpr::AO__atomic_fetch_fmaximum:
1392 case AtomicExpr::AO__atomic_fetch_fmaximum_num:
1393 case AtomicExpr::AO__atomic_fetch_fminimum:
1394 case AtomicExpr::AO__atomic_fetch_fminimum_num:
1395 case AtomicExpr::AO__scoped_atomic_fetch_fmaximum:
1396 case AtomicExpr::AO__scoped_atomic_fetch_fmaximum_num:
1397 case AtomicExpr::AO__scoped_atomic_fetch_fminimum:
1398 case AtomicExpr::AO__scoped_atomic_fetch_fminimum_num:
1399 case AtomicExpr::AO__atomic_test_and_set:
1400 case AtomicExpr::AO__atomic_clear:
1401 case AtomicExpr::AO__atomic_fetch_uinc:
1402 case AtomicExpr::AO__atomic_fetch_udec:
1403 llvm_unreachable(
"Integral atomic operations always become atomicrmw!");
1408 cgf.
cgm.
errorNYI(loc,
"emitLibCallForAtomicExpr: openCL");
1424 cgf.
cgm.
errorNYI(loc,
"emitLibCallForAtomicExpr: openCL");
1446 memTy = ty->getValueType();
1448 Expr *isWeakExpr =
nullptr;
1449 Expr *orderFailExpr =
nullptr;
1457 if (e->
getOp() == AtomicExpr::AO__c11_atomic_init) {
1469 std::optional<Expr::EvalResult> scopeConst;
1472 scopeConst.emplace(std::move(eval));
1474 switch (e->
getOp()) {
1479 case AtomicExpr::AO__c11_atomic_init:
1480 llvm_unreachable(
"already handled above with emitAtomicInit");
1482 case AtomicExpr::AO__atomic_load_n:
1483 case AtomicExpr::AO__scoped_atomic_load_n:
1484 case AtomicExpr::AO__c11_atomic_load:
1485 case AtomicExpr::AO__opencl_atomic_load:
1486 case AtomicExpr::AO__hip_atomic_load:
1487 case AtomicExpr::AO__atomic_test_and_set:
1488 case AtomicExpr::AO__atomic_clear:
1491 case AtomicExpr::AO__atomic_load:
1492 case AtomicExpr::AO__scoped_atomic_load:
1496 case AtomicExpr::AO__atomic_store:
1497 case AtomicExpr::AO__scoped_atomic_store:
1501 case AtomicExpr::AO__atomic_exchange:
1502 case AtomicExpr::AO__scoped_atomic_exchange:
1507 case AtomicExpr::AO__atomic_compare_exchange:
1508 case AtomicExpr::AO__atomic_compare_exchange_n:
1509 case AtomicExpr::AO__c11_atomic_compare_exchange_weak:
1510 case AtomicExpr::AO__c11_atomic_compare_exchange_strong:
1511 case AtomicExpr::AO__scoped_atomic_compare_exchange:
1512 case AtomicExpr::AO__scoped_atomic_compare_exchange_n:
1513 case AtomicExpr::AO__hip_atomic_compare_exchange_strong:
1514 case AtomicExpr::AO__hip_atomic_compare_exchange_weak:
1515 case AtomicExpr::AO__opencl_atomic_compare_exchange_strong:
1516 case AtomicExpr::AO__opencl_atomic_compare_exchange_weak:
1518 if (e->
getOp() == AtomicExpr::AO__atomic_compare_exchange ||
1519 e->
getOp() == AtomicExpr::AO__scoped_atomic_compare_exchange)
1524 if (e->
getOp() == AtomicExpr::AO__atomic_compare_exchange_n ||
1525 e->
getOp() == AtomicExpr::AO__atomic_compare_exchange ||
1526 e->
getOp() == AtomicExpr::AO__scoped_atomic_compare_exchange_n ||
1527 e->
getOp() == AtomicExpr::AO__scoped_atomic_compare_exchange)
1531 case AtomicExpr::AO__c11_atomic_fetch_add:
1532 case AtomicExpr::AO__c11_atomic_fetch_sub:
1543 mlir::Value scale = builder.getConstInt(loc, val1Scalar.getType(),
1545 val1Scalar = builder.createMul(loc, val1Scalar, scale);
1551 case AtomicExpr::AO__atomic_fetch_add:
1552 case AtomicExpr::AO__atomic_fetch_sub:
1553 case AtomicExpr::AO__atomic_add_fetch:
1554 case AtomicExpr::AO__atomic_sub_fetch:
1564 case AtomicExpr::AO__atomic_fetch_max:
1565 case AtomicExpr::AO__atomic_fetch_min:
1566 case AtomicExpr::AO__atomic_max_fetch:
1567 case AtomicExpr::AO__atomic_min_fetch:
1568 case AtomicExpr::AO__c11_atomic_fetch_max:
1569 case AtomicExpr::AO__c11_atomic_fetch_min:
1570 case AtomicExpr::AO__scoped_atomic_fetch_add:
1571 case AtomicExpr::AO__scoped_atomic_fetch_max:
1572 case AtomicExpr::AO__scoped_atomic_fetch_min:
1573 case AtomicExpr::AO__scoped_atomic_fetch_sub:
1574 case AtomicExpr::AO__scoped_atomic_fetch_fminimum:
1575 case AtomicExpr::AO__scoped_atomic_fetch_fmaximum:
1576 case AtomicExpr::AO__scoped_atomic_fetch_fminimum_num:
1577 case AtomicExpr::AO__scoped_atomic_fetch_fmaximum_num:
1578 case AtomicExpr::AO__scoped_atomic_add_fetch:
1579 case AtomicExpr::AO__scoped_atomic_max_fetch:
1580 case AtomicExpr::AO__scoped_atomic_min_fetch:
1581 case AtomicExpr::AO__scoped_atomic_sub_fetch:
1584 case AtomicExpr::AO__atomic_fetch_and:
1585 case AtomicExpr::AO__atomic_fetch_nand:
1586 case AtomicExpr::AO__atomic_fetch_or:
1587 case AtomicExpr::AO__atomic_fetch_xor:
1588 case AtomicExpr::AO__atomic_and_fetch:
1589 case AtomicExpr::AO__atomic_nand_fetch:
1590 case AtomicExpr::AO__atomic_or_fetch:
1591 case AtomicExpr::AO__atomic_xor_fetch:
1592 case AtomicExpr::AO__atomic_exchange_n:
1593 case AtomicExpr::AO__atomic_store_n:
1594 case AtomicExpr::AO__c11_atomic_fetch_and:
1595 case AtomicExpr::AO__c11_atomic_fetch_nand:
1596 case AtomicExpr::AO__c11_atomic_fetch_or:
1597 case AtomicExpr::AO__c11_atomic_fetch_xor:
1598 case AtomicExpr::AO__c11_atomic_exchange:
1599 case AtomicExpr::AO__c11_atomic_store:
1600 case AtomicExpr::AO__scoped_atomic_fetch_and:
1601 case AtomicExpr::AO__scoped_atomic_fetch_nand:
1602 case AtomicExpr::AO__scoped_atomic_fetch_or:
1603 case AtomicExpr::AO__scoped_atomic_fetch_xor:
1604 case AtomicExpr::AO__scoped_atomic_and_fetch:
1605 case AtomicExpr::AO__scoped_atomic_nand_fetch:
1606 case AtomicExpr::AO__scoped_atomic_or_fetch:
1607 case AtomicExpr::AO__scoped_atomic_xor_fetch:
1608 case AtomicExpr::AO__scoped_atomic_store_n:
1609 case AtomicExpr::AO__scoped_atomic_exchange_n:
1610 case AtomicExpr::AO__atomic_fetch_uinc:
1611 case AtomicExpr::AO__atomic_fetch_udec:
1612 case AtomicExpr::AO__scoped_atomic_fetch_uinc:
1613 case AtomicExpr::AO__scoped_atomic_fetch_udec:
1614 case AtomicExpr::AO__atomic_fetch_fminimum:
1615 case AtomicExpr::AO__atomic_fetch_fmaximum:
1616 case AtomicExpr::AO__atomic_fetch_fminimum_num:
1617 case AtomicExpr::AO__atomic_fetch_fmaximum_num:
1618 case AtomicExpr::AO__hip_atomic_exchange:
1619 case AtomicExpr::AO__hip_atomic_store:
1620 case AtomicExpr::AO__hip_atomic_fetch_add:
1621 case AtomicExpr::AO__hip_atomic_fetch_sub:
1622 case AtomicExpr::AO__hip_atomic_fetch_min:
1623 case AtomicExpr::AO__hip_atomic_fetch_max:
1624 case AtomicExpr::AO__hip_atomic_fetch_and:
1625 case AtomicExpr::AO__hip_atomic_fetch_or:
1626 case AtomicExpr::AO__hip_atomic_fetch_xor:
1627 case AtomicExpr::AO__opencl_atomic_exchange:
1628 case AtomicExpr::AO__opencl_atomic_store:
1629 case AtomicExpr::AO__opencl_atomic_fetch_add:
1630 case AtomicExpr::AO__opencl_atomic_fetch_sub:
1631 case AtomicExpr::AO__opencl_atomic_fetch_min:
1632 case AtomicExpr::AO__opencl_atomic_fetch_max:
1633 case AtomicExpr::AO__opencl_atomic_fetch_and:
1634 case AtomicExpr::AO__opencl_atomic_fetch_or:
1635 case AtomicExpr::AO__opencl_atomic_fetch_xor:
1642 bool shouldCastToIntPtrTy =
1650 AtomicInfo atomics(*
this, atomicValue, loc);
1656 if (shouldCastToIntPtrTy) {
1657 ptr = atomics.castToAtomicIntPointer(ptr);
1659 val1 = atomics.convertToAtomicIntPointer(val1, loc);
1661 val2 = atomics.convertToAtomicIntPointer(val2, loc);
1664 if (shouldCastToIntPtrTy)
1665 dest = atomics.castToAtomicIntPointer(dest);
1668 }
else if (e->
getOp() == AtomicExpr::AO__atomic_test_and_set) {
1671 dest = atomics.createTempAlloca();
1672 if (shouldCastToIntPtrTy)
1673 dest = atomics.castToAtomicIntPointer(dest);
1676 bool powerOf2Size = (size & (size - 1)) == 0;
1677 bool useLibCall = !powerOf2Size || (size > 16);
1692 bool isStore = e->
getOp() == AtomicExpr::AO__c11_atomic_store ||
1693 e->
getOp() == AtomicExpr::AO__opencl_atomic_store ||
1694 e->
getOp() == AtomicExpr::AO__hip_atomic_store ||
1695 e->
getOp() == AtomicExpr::AO__atomic_store ||
1696 e->
getOp() == AtomicExpr::AO__atomic_store_n ||
1697 e->
getOp() == AtomicExpr::AO__scoped_atomic_store ||
1698 e->
getOp() == AtomicExpr::AO__scoped_atomic_store_n ||
1699 e->
getOp() == AtomicExpr::AO__atomic_clear;
1700 bool isLoad = e->
getOp() == AtomicExpr::AO__c11_atomic_load ||
1701 e->
getOp() == AtomicExpr::AO__opencl_atomic_load ||
1702 e->
getOp() == AtomicExpr::AO__hip_atomic_load ||
1703 e->
getOp() == AtomicExpr::AO__atomic_load ||
1704 e->
getOp() == AtomicExpr::AO__atomic_load_n ||
1705 e->
getOp() == AtomicExpr::AO__scoped_atomic_load ||
1706 e->
getOp() == AtomicExpr::AO__scoped_atomic_load_n;
1708 auto emitAtomicOpCallBackFn = [&](cir::MemOrder memOrder) {
1709 emitAtomicOp(*
this, e, dest, ptr, val1, val2, originalVal1, isWeakExpr,
1710 orderFailExpr, size, memOrder, scopeConst, scope);
1713 emitAtomicOpCallBackFn);
1726 return emitAtomicLoad(lvalue, loc, cir::MemOrder::SequentiallyConsistent,
1733 cir::MemOrder order,
bool isVolatile,
1735 AtomicInfo info(*
this, lvalue,
getLoc(loc));
1736 return info.emitAtomicLoad(slot, loc,
true, order, isVolatile);
1741 auto order = cir::MemOrder::SequentiallyConsistent;
1754 cir::MemOrder order,
bool isVolatile,
1758 mlir::Location loc = dest.
getPointer().getLoc();
1763 AtomicInfo atomics(*
this, dest, loc);
1764 LValue lvalue = atomics.getAtomicLValue();
1769 atomics.emitCopyIntoMemory(rvalue);
1774 if (atomics.shouldUseLibCall()) {
1776 cgm.errorNYI(loc,
"emitAtomicStore: atomic store with library call");
1781 mlir::Value valueToStore = atomics.convertRValueToInt(rvalue, loc);
1784 Address addr = atomics.getAtomicAddress();
1785 if (mlir::Value value = atomics.getScalarRValValueOrNull(rvalue)) {
1787 addr = atomics.castToAtomicIntPointer(addr);
1792 cir::StoreOp store = builder.createStore(loc, valueToStore, addr);
1797 store.setMemOrder(order);
1802 store.setIsVolatile(
true);
1808 cgm.errorNYI(loc,
"emitAtomicStore: non-simple atomic lvalue");
1815 switch (atomics.getEvaluationKind()) {
1831 bool zeroed =
false;
1833 zeroed = atomics.emitMemSetZeroIfNecessary();
1834 dest = atomics.projectValue();
1849 llvm_unreachable(
"bad evaluation kind");
static bool shouldCastToInt(mlir::Type valueTy, bool cmpxchg)
Return true if.
static Address emitValToTemp(CIRGenFunction &cgf, Expr *e)
static void emitMemOrderCaseLabel(CIRGenBuilderTy &builder, mlir::Location loc, mlir::Type orderType, llvm::ArrayRef< cir::MemOrder > orders)
static cir::SyncScopeKind convertSyncScopeToCIR(CIRGenFunction &cgf, SourceRange range, clang::SyncScope scope)
static RValue emitLibCallForAtomicExpr(CIRGenFunction &cgf, AtomicExpr *e, Address atomicPtr, Address dest, Address val1, Address val2, uint64_t atomicTySize, QualType resultTy)
static void emitAtomicExprWithDynamicMemOrder(CIRGenFunction &cgf, mlir::Value order, bool isStore, bool isLoad, bool isFence, llvm::function_ref< void(cir::MemOrder)> emitAtomicOpFn)
static void emitDefaultCaseLabel(CIRGenBuilderTy &builder, mlir::Location loc)
static void emitAtomicCmpXchgFailureSetCheckWeak(CIRGenFunction &cgf, AtomicExpr *e, Expr *isWeakExpr, Address dest, Address ptr, Address val1, Address val2, Address expectedResult, Expr *failureOrderExpr, uint64_t size, cir::MemOrder successOrder, cir::SyncScopeKind scope)
static void setAMDGPUAtomicMetadata(CIRGenFunction &cgf, mlir::Operation *op, const AtomicExpr *expr)
Attach the AMDGPU atomic metadata markers that the current atomic options call for.
static bool isFullSizeType(CIRGenModule &cgm, mlir::Type ty, uint64_t expectedSize)
Does a store of the given IR type modify the full expected width?
static void emitAtomicCmpXchgFailureSet(CIRGenFunction &cgf, AtomicExpr *e, bool isWeak, Address dest, Address ptr, Address val1, Address val2, Address expectedResult, Expr *failureOrderExpr, uint64_t size, cir::MemOrder successOrder, cir::SyncScopeKind scope)
static void emitAtomicCmpXchg(CIRGenFunction &cgf, AtomicExpr *e, bool isWeak, Address dest, Address ptr, Address val1, Address val2, Address expectedResult, uint64_t size, cir::MemOrder successOrder, cir::MemOrder failureOrder, cir::SyncScopeKind scope)
static void emitAtomicOp(CIRGenFunction &cgf, AtomicExpr *expr, Address dest, Address ptr, Address val1, Address val2, Address expectedResult, Expr *isWeakExpr, Expr *failureOrderExpr, int64_t size, cir::MemOrder order, cir::SyncScopeKind scope)
static std::optional< cir::MemOrder > getEffectiveAtomicMemOrder(cir::MemOrder oriOrder, bool isStore, bool isLoad, bool isFence)
static RValue emitAtomicLibCall(CIRGenFunction &cgf, llvm::StringRef funcName, QualType resultType, CallArgList &args)
*collection of selector each with an associated kind and an ordered *collection of selectors A selector has a kind
cir::BreakOp createBreak(mlir::Location loc)
Create a break operation.
mlir::Value createPtrBitcast(mlir::Value src, mlir::Type newPointeeTy)
mlir::Value createNot(mlir::Location loc, mlir::Value value)
cir::YieldOp createYield(mlir::Location loc, mlir::ValueRange value={})
Create a yield operation.
cir::BoolType getBoolTy()
llvm::TypeSize getTypeSizeInBits(mlir::Type ty) const
llvm::TypeSize getTypeStoreSize(mlir::Type ty) const
Returns the maximum number of bytes that may be overwritten by storing the specified type.
TypeInfo getTypeInfo(const Type *T) const
Get the size and alignment of the specified complete type in bits.
int64_t toBits(CharUnits CharSize) const
Convert a size in characters to a size in bits.
QualType getSizeType() const
Return the unique type for "size_t" (C99 7.17), defined in <stddef.h>.
const TargetInfo & getTargetInfo() const
CharUnits toCharUnitsFromBits(int64_t BitSize) const
Convert a size in bits to a size in characters.
AtomicExpr - Variadic atomic builtins: __atomic_exchange, __atomic_fetch_*, __atomic_load,...
static std::unique_ptr< AtomicScopeModel > getScopeModel(AtomicOp Op)
Get atomic scope model for the atomic op code.
Expr * getOrderFail() const
mlir::Value getPointer() const
mlir::Type getElementType() const
Address withElementType(CIRGenBuilderTy &builder, mlir::Type ElemTy) const
Return address with different element type, a bitcast pointer, and the same alignment.
clang::CharUnits getAlignment() const
mlir::Value emitRawPointer() const
Return the pointer contained in this class after authenticating it and adding offset to it if necessa...
static AggValueSlot forLValue(const LValue &LV, IsDestructed_t isDestructed, IsAliased_t isAliased, Overlap_t mayOverlap, IsZeroed_t isZeroed=IsNotZeroed)
Address getAddress() const
cir::LoadOp createLoad(mlir::Location loc, Address addr, bool isVolatile=false, bool isNontemporal=false)
cir::StoreOp createStore(mlir::Location loc, mlir::Value val, Address dst, bool isVolatile=false, bool isNontemporal=false, mlir::IntegerAttr align={}, cir::SyncScopeKindAttr scope={}, cir::MemOrderAttr order={})
cir::MemCpyOp createMemCpy(mlir::Location loc, Address dst, Address src, mlir::Value len)
cir::ConstantOp getConstInt(mlir::Location loc, llvm::APSInt intVal)
cir::MemSetOp createMemSet(mlir::Location loc, mlir::Value dst, mlir::Value val, mlir::Value len)
cir::IntType getUIntNTy(int n)
static CIRGenCallee forDirect(mlir::Operation *funcPtr, const CIRGenCalleeInfo &abstractInfo=CIRGenCalleeInfo())
RValue convertTempToRValue(Address addr, clang::QualType type, clang::SourceLocation loc)
Given the address of a temporary variable, produce an r-value of its type.
Address emitPointerWithAlignment(const clang::Expr *expr, LValueBaseInfo *baseInfo=nullptr)
Given an expression with a pointer type, emit the value and compute our best estimate of the alignmen...
cir::AllocaOp createTempAlloca(mlir::Type ty, mlir::Location loc, const Twine &name="tmp", mlir::Value arraySize=nullptr, bool insertIntoFnEntryBlock=false)
This creates an alloca and inserts it into the entry block if ArraySize is nullptr,...
mlir::Value emitComplexExpr(const Expr *e)
Emit the computation of the specified expression of complex type, returning the result.
mlir::Location getLoc(clang::SourceLocation srcLoc)
Helpers to convert Clang's SourceLocation to a MLIR Location.
void emitAnyExprToMem(const Expr *e, Address location, Qualifiers quals, bool isInitializer)
Emits the code necessary to evaluate an arbitrary expression into the given memory location.
RValue emitAtomicExpr(AtomicExpr *e)
RValue emitAtomicLoad(LValue lvalue, SourceLocation loc, AggValueSlot slot=AggValueSlot::ignored())
mlir::Type convertTypeForMem(QualType t)
void emitStoreOfScalar(mlir::Value value, Address addr, bool isVolatile, clang::QualType ty, LValueBaseInfo baseInfo, bool isInit=false, bool isNontemporal=false)
void emitStoreOfComplex(mlir::Location loc, mlir::Value v, LValue dest, bool isInit)
EmitStoreOfComplex - Store a complex number into the specified l-value.
void emitAtomicExprWithMemOrder(const Expr *memOrder, bool isStore, bool isLoad, bool isFence, llvm::function_ref< void(cir::MemOrder)> emitAtomicOp)
mlir::Value emitToMemory(mlir::Value value, clang::QualType ty)
Given a value and its clang type, returns the value casted to its memory representation.
mlir::Value emitScalarExpr(const clang::Expr *e, bool ignoreResultAssign=false)
Emit the computation of the specified expression of scalar type.
CIRGenBuilderTy & getBuilder()
mlir::MLIRContext & getMLIRContext()
void emitAtomicInit(Expr *init, LValue dest)
RValue emitCall(const CIRGenFunctionInfo &funcInfo, const CIRGenCallee &callee, ReturnValueSlot returnValue, const CallArgList &args, cir::CIRCallOpInterface *callOp, bool isMustTail, SourceRange clangLoc)
LValue makeAddrLValue(Address addr, QualType ty, AlignmentSource source=AlignmentSource::Type)
void emitAtomicStore(RValue rvalue, LValue dest, bool isInit)
clang::ASTContext & getContext() const
mlir::Value emitFromMemory(mlir::Value value, clang::QualType ty)
EmitFromMemory - Change a scalar value from its memory representation to its value representation.
Address createMemTemp(QualType t, mlir::Location loc, const Twine &name="tmp", Address *alloca=nullptr, mlir::OpBuilder::InsertPoint ip={})
Create a temporary memory object of the given type, with appropriate alignmen and cast it to the defa...
void emitAggExpr(const clang::Expr *e, AggValueSlot slot)
This class organizes the cross-function state that is used while generating CIR code.
DiagnosticBuilder errorNYI(SourceLocation, llvm::StringRef)
Helpers to emit "not yet implemented" error diagnostics.
clang::AtomicOptions getAtomicOpts() const
The atomic options in effect at the point currently being emitted.
const llvm::Triple & getTriple() const
const cir::CIRDataLayout & getDataLayout() const
cir::FuncOp createRuntimeFunction(cir::FuncType ty, llvm::StringRef name, mlir::NamedAttrList extraAttrs={}, bool isLocal=false, bool assumeConvergent=false)
const CIRGenFunctionInfo & arrangeBuiltinFunctionCall(QualType resultType, const CallArgList &args)
A builtin function is a freestanding function using the default C conventions.
cir::FuncType getFunctionType(const CIRGenFunctionInfo &info)
Get the CIR function type for.
void add(RValue rvalue, clang::QualType type)
Address getAddress() const
clang::QualType getType() const
mlir::Value getPointer() const
bool isVolatileQualified() const
This trivial value class is used to represent the result of an expression that is evaluated.
Address getAggregateAddress() const
Return the value of the address of the aggregate.
static RValue get(mlir::Value v)
static RValue getAggregate(Address addr, bool isVolatile=false)
Convert an Address to an RValue.
mlir::Value getValue() const
Return the value of this scalar value.
mlir::Value getComplexValue() const
Return the value of this complex value.
Contains the address where the return value of a function can be stored, and whether the address is v...
This is an opaque type for sizes expressed in character units.
llvm::Align getAsAlign() const
Returns Quantity as a valid llvm::Align, Beware llvm::Align assumes power of two 8-bit bytes.
QuantityType getQuantity() const
Get the raw integer representation of this quantity.
This represents one expression.
bool EvaluateAsInt(EvalResult &Result, const ASTContext &Ctx, SideEffectsKind AllowSideEffects=SE_NoSideEffects, bool InConstantContext=false) const
EvaluateAsInt - Return true if this is a constant which we can fold and convert to an integer,...
bool EvaluateAsBooleanCondition(bool &Result, const ASTContext &Ctx, bool InConstantContext=false) const
EvaluateAsBooleanCondition - Return true if this is a constant which we can fold and convert to a boo...
SourceLocation getExprLoc() const LLVM_READONLY
getExprLoc - Return the preferred location for the arrow when diagnosing a problem with a generic exp...
A (possibly-)qualified type.
Qualifiers getQualifiers() const
Retrieve the set of qualifiers applied to this type.
QualType getUnqualifiedType() const
Retrieve the unqualified variant of the given type, removing as little sugar as possible.
Encodes a location in the source.
A trivial tuple used to represent a source range.
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
virtual bool hasBuiltinAtomic(uint64_t AtomicSizeInBits, uint64_t AlignmentInBits) const
Returns true if the given target supports lock-free atomic operations at the specified width and alig...
bool isPointerType() const
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
bool isAtomicType() const
const T * getAs() const
Member-template getAs<specific type>'.
bool isValidCIRAtomicOrderingCABI(Int value)
const internal::VariadicDynCastAllOfMatcher< Stmt, Expr > expr
Matches expressions.
@ Address
A pointer to a ValueDecl.
Top level wrappers for InstallAPI frontend operations.
bool isa(CodeGen::Address addr)
SyncScope
Defines sync scope values used internally by clang.
static bool atomicAMDGPUAvailableVisibleMMRA()
static bool atomicInfoGetAtomicPointer()
static bool aggValueSlotGC()
static bool opLoadStoreAtomic()
static bool opLoadStoreTbaa()
static bool opFuncExtraAttrs()
static bool atomicUseLibCall()
static bool atomicOpenMP()
static bool atomicMicrosoftVolatile()
static bool atomicSyncScopeID()
static bool generateDebugInfo()
static bool atomicInfoGetAtomicAddress()
bool getOption(AtomicOptionKind Kind) const
EvalResult is a struct with detailed info about an evaluated expression.
APValue Val
Val - This is the value the expression can be folded to.