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 bool isAMDGCN = triple.isAMDGCN();
176 bool isAMDSPIRV = triple.isSPIRV() && triple.getVendor() == llvm::Triple::AMD;
177 if (!isAMDGCN && !isAMDSPIRV)
181 mlir::UnitAttr unit = cgf.
getBuilder().getUnitAttr();
182 if (isAMDGCN &&
expr->threadPrivateMemoryAtomicsAreUndefined())
183 op->setAttr(cir::CIRDialect::getAMDGPUNoPrivateAddrSpaceAttrName(), unit);
187 if (!mlir::isa<cir::AtomicFetchOp, cir::AtomicXchgOp>(op))
192 op->setAttr(cir::CIRDialect::getAMDGPUNoFineGrainedMemoryAttrName(), unit);
194 op->setAttr(cir::CIRDialect::getAMDGPUNoRemoteMemoryAttrName(), unit);
196 auto fetchOp = mlir::dyn_cast<cir::AtomicFetchOp>(op);
199 fetchOp.getBinop() == cir::AtomicFetchKind::Add &&
200 mlir::isa<cir::SingleType>(fetchOp.getVal().getType()))
201 op->setAttr(cir::CIRDialect::getAMDGPUIgnoreDenormalModeAttrName(), unit);
216 uint64_t expectedSize) {
223bool AtomicInfo::requiresMemSetZero(mlir::Type ty)
const {
229 switch (getEvaluationKind()) {
236 mlir::cast<cir::ComplexType>(ty).getElementType(),
237 atomicSizeInBits / 2);
242 llvm_unreachable(
"bad evaluation kind");
245Address AtomicInfo::convertToAtomicIntPointer(Address addr,
246 mlir::Location loc)
const {
249 if (sourceSizeInBits != atomicSizeInBits) {
252 Address tmp = createTempAlloca();
264 std::min(atomicSizeInBits, sourceSizeInBits) / 8));
268 return castToAtomicIntPointer(addr);
271RValue AtomicInfo::convertAtomicTempToRValue(Address addr,
272 AggValueSlot resultSlot,
274 bool asValue)
const {
275 if (lvalue.isSimple()) {
282 "AtomicInfo::convertAtomicTempToRValue: hasPadding");
292 loc,
"AtomicInfo::convertAtomicTempToRValue: lvalue is not simple");
296RValue AtomicInfo::emitAtomicLoad(AggValueSlot resultSlot, SourceLocation loc,
297 bool asValue, cir::MemOrder order,
300 if (shouldUseLibCall()) {
302 cgf.
cgm.
errorNYI(loc,
"emitAtomicLoad: emit atomic lib call");
307 mlir::Value loadOp = emitAtomicLoadOp(order, isVolatile);
315 return convertToValueOrAtomic(loadOp, resultSlot, loc, asValue);
318Address AtomicInfo::createTempAlloca()
const {
321 QualType tmpTy = (lvalue.isBitField() && valueSizeInBits > atomicSizeInBits)
325 cgf.
createMemTemp(tmpTy, getAtomicAlignment(), loc,
"atomic-temp");
328 if (lvalue.isBitField()) {
329 cgf.
cgm.
errorNYI(loc,
"AtomicInfo::createTempAlloca: bitfield lvalue");
335mlir::Value AtomicInfo::getScalarRValValueOrNull(RValue rvalue)
const {
336 if (rvalue.
isScalar() && (!hasPadding() || !lvalue.isSimple()))
341Address AtomicInfo::castToAtomicIntPointer(Address addr)
const {
344 if (intTy && intTy.getWidth() == atomicSizeInBits)
350bool AtomicInfo::emitMemSetZeroIfNecessary()
const {
351 assert(lvalue.isSimple());
352 Address addr = lvalue.getAddress();
372 if (cir::isAnyFloatingPointType(valueTy))
377mlir::Value AtomicInfo::emitAtomicLoadOp(cir::MemOrder order,
bool isVolatile,
379 Address addr = getAtomicAddress();
381 addr = castToAtomicIntPointer(addr);
385 op.setMemOrder(order);
391mlir::Value AtomicInfo::convertRValueToInt(RValue rvalue, mlir::Location loc,
392 bool cmpxchg)
const {
395 if (mlir::Value value = getScalarRValValueOrNull(rvalue)) {
400 loc,
"AtomicInfo::convertRValueToInt: cast scalar rvalue to int");
406 Address addr = materializeRValue(rvalue, loc);
409 addr = castToAtomicIntPointer(addr);
414RValue AtomicInfo::convertToValueOrAtomic(mlir::Value intVal,
415 AggValueSlot resultSlot,
416 SourceLocation loc,
bool asValue,
417 bool cmpxchg)
const {
419 assert((mlir::isa<cir::IntType, cir::PointerType, cir::FPTypeInterface>(
420 intVal.getType())) &&
421 "Expected integer, pointer or floating point value when converting "
424 !lvalue.isBitField() || lvalue.getBitFieldInfo().size == valueSizeInBits;
426 ((isWholeValue && !hasPadding()) || !asValue)) {
428 : getAtomicAddress().getElementType();
430 assert((!mlir::isa<cir::IntType>(valTy) || intVal.getType() == valTy) &&
431 "Different integer types.");
435 cgf.
cgm.
errorNYI(
"convertToValueOrAtomic: convert through bitcast");
442 bool tempIsVolatile =
false;
448 temp = createTempAlloca();
452 Address castTemp = castToAtomicIntPointer(temp);
455 return convertAtomicTempToRValue(temp, resultSlot, loc, asValue);
460void AtomicInfo::emitCopyIntoMemory(RValue rvalue)
const {
461 assert(lvalue.isSimple());
467 cgf.
cgm.
errorNYI(
"copying aggregate into atomic lvalue");
474 emitMemSetZeroIfNecessary();
477 LValue tempLValue = projectValue();
490Address AtomicInfo::materializeRValue(RValue rvalue, mlir::Location loc)
const {
497 LValue tempLV = cgf.
makeAddrLValue(createTempAlloca(), getAtomicType());
498 AtomicInfo atomics(cgf, tempLV, loc);
500 atomics.emitCopyIntoMemory(rvalue);
501 return tempLV.getAddress();
505 mlir::ArrayAttr valuesAttr = builder.getArrayAttr({});
506 mlir::OpBuilder::InsertPoint insertPoint;
507 cir::CaseOp::create(builder, loc, valuesAttr, cir::CaseOpKind::Default,
509 builder.restoreInsertionPoint(insertPoint);
515 mlir::Type orderType,
518 for (cir::MemOrder order : orders)
519 orderAttrs.push_back(cir::IntAttr::get(orderType,
static_cast<int>(order)));
520 mlir::ArrayAttr ordersAttr = builder.getArrayAttr(orderAttrs);
522 mlir::OpBuilder::InsertPoint insertPoint;
523 cir::CaseOp::create(builder, loc, ordersAttr, cir::CaseOpKind::Anyof,
525 builder.restoreInsertionPoint(insertPoint);
531 uint64_t size, cir::MemOrder successOrder,
532 cir::MemOrder failureOrder,
533 cir::SyncScopeKind scope) {
537 mlir::Value expected = builder.
createLoad(loc, val1);
538 mlir::Value desired = builder.
createLoad(loc, val2);
540 auto cmpxchg = cir::AtomicCmpXchgOp::create(
549 cmpxchg.setWeak(isWeak);
552 mlir::Value failed = builder.
createNot(cmpxchg.getSuccess());
554 builder, loc, failed,
false,
555 [&](mlir::OpBuilder &, mlir::Location) {
559 if (expectedSizeInBytes == size) {
561 builder, cmpxchg.getOld().getType());
562 builder.
createStore(loc, cmpxchg.getOld(), storeAddr);
566 cmpxchg.getOld().getType(), ptr.
getAlignment(), loc,
"old.tmp");
567 builder.
createStore(loc, cmpxchg.getOld(), oldTmp);
574 loc, expectedVoid, oldTmpVoid,
589 uint64_t size, cir::MemOrder successOrder, cir::SyncScopeKind scope) {
592 uint64_t failureOrderInt = failureOrderEval.
Val.
getInt().getZExtValue();
594 cir::MemOrder failureOrder;
596 failureOrder = cir::MemOrder::Relaxed;
598 switch ((cir::MemOrder)failureOrderInt) {
599 case cir::MemOrder::Relaxed:
602 case cir::MemOrder::Release:
603 case cir::MemOrder::AcquireRelease:
604 failureOrder = cir::MemOrder::Relaxed;
606 case cir::MemOrder::Consume:
607 case cir::MemOrder::Acquire:
608 failureOrder = cir::MemOrder::Acquire;
610 case cir::MemOrder::SequentiallyConsistent:
611 failureOrder = cir::MemOrder::SequentiallyConsistent;
621 size, successOrder, failureOrder, scope);
629 mlir::Value failureOrderVal = cgf.
emitScalarExpr(failureOrderExpr);
631 cir::SwitchOp::create(
633 [&](mlir::OpBuilder &b, mlir::Location loc, mlir::OperationState &os) {
634 mlir::Block *switchBlock = cgf.getBuilder().getBlock();
646 emitDefaultCaseLabel(cgf.getBuilder(), atomicLoc);
647 emitAtomicCmpXchg(cgf, e, isWeak, dest, ptr, val1, val2, expectedResult,
648 size, successOrder, cir::MemOrder::Relaxed, scope);
649 cgf.getBuilder().createBreak(atomicLoc);
650 cgf.getBuilder().setInsertionPointToEnd(switchBlock);
654 emitMemOrderCaseLabel(cgf.getBuilder(), loc, failureOrderVal.getType(),
655 {cir::MemOrder::Consume, cir::MemOrder::Acquire});
657 size, successOrder, cir::MemOrder::Acquire, scope);
659 cgf.
getBuilder().setInsertionPointToEnd(switchBlock);
663 {cir::MemOrder::SequentiallyConsistent});
666 cir::MemOrder::SequentiallyConsistent, scope);
668 cgf.
getBuilder().setInsertionPointToEnd(switchBlock);
680 Expr *failureOrderExpr, uint64_t size, cir::MemOrder successOrder,
681 cir::SyncScopeKind scope) {
693 [&](mlir::OpBuilder &b, mlir::Location loc) {
694 emitAtomicCmpXchgFailureSet(cgf, e, true, dest, ptr, val1,
695 val2, expectedResult, failureOrderExpr,
696 size, successOrder, scope);
697 cgf.getBuilder().createYield(atomicLoc);
699 [&](mlir::OpBuilder &b, mlir::Location loc) {
700 emitAtomicCmpXchgFailureSet(cgf, e, false, dest, ptr, val1,
701 val2, expectedResult, failureOrderExpr,
702 size, successOrder, scope);
703 cgf.getBuilder().createYield(atomicLoc);
711 cir::MemOrder order, cir::SyncScopeKind scope) {
713 llvm::StringRef opName;
716 mlir::Location loc = cgf.
getLoc(
expr->getSourceRange());
717 auto orderAttr = cir::MemOrderAttr::get(builder.getContext(), order);
718 auto scopeAttr = cir::SyncScopeKindAttr::get(builder.getContext(), scope);
719 cir::AtomicFetchKindAttr fetchAttr;
720 bool fetchFirst =
true;
722 auto handleFetchOp = [&](cir::AtomicFetchKind
kind) {
723 opName = cir::AtomicFetchOp::getOperationName();
724 fetchAttr = cir::AtomicFetchKindAttr::get(builder.getContext(),
kind);
727 switch (
expr->getOp()) {
728 case AtomicExpr::AO__c11_atomic_init:
729 llvm_unreachable(
"already handled!");
731 case AtomicExpr::AO__c11_atomic_compare_exchange_strong:
732 case AtomicExpr::AO__hip_atomic_compare_exchange_strong:
733 case AtomicExpr::AO__opencl_atomic_compare_exchange_strong:
735 val2, expectedResult, failureOrderExpr, size,
739 case AtomicExpr::AO__c11_atomic_compare_exchange_weak:
740 case AtomicExpr::AO__hip_atomic_compare_exchange_weak:
741 case AtomicExpr::AO__opencl_atomic_compare_exchange_weak:
743 val2, expectedResult, failureOrderExpr, size,
747 case AtomicExpr::AO__atomic_compare_exchange:
748 case AtomicExpr::AO__atomic_compare_exchange_n:
749 case AtomicExpr::AO__scoped_atomic_compare_exchange:
750 case AtomicExpr::AO__scoped_atomic_compare_exchange_n: {
754 expectedResult, failureOrderExpr, size, order,
758 cgf,
expr, isWeakExpr, dest, ptr, val1, val2, expectedResult,
759 failureOrderExpr, size, order, scope);
764 case AtomicExpr::AO__c11_atomic_load:
765 case AtomicExpr::AO__atomic_load_n:
766 case AtomicExpr::AO__atomic_load:
767 case AtomicExpr::AO__scoped_atomic_load_n:
768 case AtomicExpr::AO__scoped_atomic_load:
769 case AtomicExpr::AO__hip_atomic_load:
770 case AtomicExpr::AO__opencl_atomic_load: {
774 load->setAttr(
"mem_order", orderAttr);
775 load->setAttr(
"sync_scope", scopeAttr);
777 builder.
createStore(loc, load->getResult(0), dest);
781 case AtomicExpr::AO__c11_atomic_store:
782 case AtomicExpr::AO__atomic_store_n:
783 case AtomicExpr::AO__atomic_store:
784 case AtomicExpr::AO__scoped_atomic_store:
785 case AtomicExpr::AO__scoped_atomic_store_n:
786 case AtomicExpr::AO__hip_atomic_store:
787 case AtomicExpr::AO__opencl_atomic_store: {
788 cir::LoadOp loadVal1 = builder.
createLoad(loc, val1);
794 mlir::IntegerAttr{}, scopeAttr, orderAttr);
798 case AtomicExpr::AO__c11_atomic_exchange:
799 case AtomicExpr::AO__atomic_exchange_n:
800 case AtomicExpr::AO__atomic_exchange:
801 case AtomicExpr::AO__scoped_atomic_exchange_n:
802 case AtomicExpr::AO__scoped_atomic_exchange:
803 case AtomicExpr::AO__hip_atomic_exchange:
804 case AtomicExpr::AO__opencl_atomic_exchange:
805 opName = cir::AtomicXchgOp::getOperationName();
808 case AtomicExpr::AO__atomic_add_fetch:
809 case AtomicExpr::AO__scoped_atomic_add_fetch:
812 case AtomicExpr::AO__c11_atomic_fetch_add:
813 case AtomicExpr::AO__atomic_fetch_add:
814 case AtomicExpr::AO__scoped_atomic_fetch_add:
815 case AtomicExpr::AO__hip_atomic_fetch_add:
816 case AtomicExpr::AO__opencl_atomic_fetch_add:
817 handleFetchOp(cir::AtomicFetchKind::Add);
820 case AtomicExpr::AO__atomic_sub_fetch:
821 case AtomicExpr::AO__scoped_atomic_sub_fetch:
824 case AtomicExpr::AO__c11_atomic_fetch_sub:
825 case AtomicExpr::AO__atomic_fetch_sub:
826 case AtomicExpr::AO__scoped_atomic_fetch_sub:
827 case AtomicExpr::AO__hip_atomic_fetch_sub:
828 case AtomicExpr::AO__opencl_atomic_fetch_sub:
829 handleFetchOp(cir::AtomicFetchKind::Sub);
832 case AtomicExpr::AO__atomic_min_fetch:
833 case AtomicExpr::AO__scoped_atomic_min_fetch:
836 case AtomicExpr::AO__c11_atomic_fetch_min:
837 case AtomicExpr::AO__atomic_fetch_min:
838 case AtomicExpr::AO__scoped_atomic_fetch_min:
839 case AtomicExpr::AO__hip_atomic_fetch_min:
840 case AtomicExpr::AO__opencl_atomic_fetch_min:
841 handleFetchOp(cir::AtomicFetchKind::Min);
844 case AtomicExpr::AO__atomic_fetch_fminimum:
845 case AtomicExpr::AO__scoped_atomic_fetch_fminimum:
846 assert(
expr->getValueType()->isFloatingType() &&
847 "fminimum operations only support floating-point types");
848 handleFetchOp(cir::AtomicFetchKind::Minimum);
851 case AtomicExpr::AO__atomic_fetch_fminimum_num:
852 case AtomicExpr::AO__scoped_atomic_fetch_fminimum_num:
853 assert(
expr->getValueType()->isFloatingType() &&
854 "fminimum_num operations only support floating-point types");
855 handleFetchOp(cir::AtomicFetchKind::MinimumNum);
858 case AtomicExpr::AO__atomic_max_fetch:
859 case AtomicExpr::AO__scoped_atomic_max_fetch:
862 case AtomicExpr::AO__c11_atomic_fetch_max:
863 case AtomicExpr::AO__atomic_fetch_max:
864 case AtomicExpr::AO__scoped_atomic_fetch_max:
865 case AtomicExpr::AO__hip_atomic_fetch_max:
866 case AtomicExpr::AO__opencl_atomic_fetch_max:
867 handleFetchOp(cir::AtomicFetchKind::Max);
870 case AtomicExpr::AO__atomic_fetch_fmaximum:
871 case AtomicExpr::AO__scoped_atomic_fetch_fmaximum:
872 assert(
expr->getValueType()->isFloatingType() &&
873 "fmaximum operations only support floating-point types");
874 handleFetchOp(cir::AtomicFetchKind::Maximum);
877 case AtomicExpr::AO__atomic_fetch_fmaximum_num:
878 case AtomicExpr::AO__scoped_atomic_fetch_fmaximum_num:
879 assert(
expr->getValueType()->isFloatingType() &&
880 "fmaximum_num operations only support floating-point types");
881 handleFetchOp(cir::AtomicFetchKind::MaximumNum);
884 case AtomicExpr::AO__atomic_and_fetch:
885 case AtomicExpr::AO__scoped_atomic_and_fetch:
888 case AtomicExpr::AO__c11_atomic_fetch_and:
889 case AtomicExpr::AO__atomic_fetch_and:
890 case AtomicExpr::AO__scoped_atomic_fetch_and:
891 case AtomicExpr::AO__hip_atomic_fetch_and:
892 case AtomicExpr::AO__opencl_atomic_fetch_and:
893 handleFetchOp(cir::AtomicFetchKind::And);
896 case AtomicExpr::AO__atomic_or_fetch:
897 case AtomicExpr::AO__scoped_atomic_or_fetch:
900 case AtomicExpr::AO__c11_atomic_fetch_or:
901 case AtomicExpr::AO__atomic_fetch_or:
902 case AtomicExpr::AO__scoped_atomic_fetch_or:
903 case AtomicExpr::AO__hip_atomic_fetch_or:
904 case AtomicExpr::AO__opencl_atomic_fetch_or:
905 handleFetchOp(cir::AtomicFetchKind::Or);
908 case AtomicExpr::AO__atomic_xor_fetch:
909 case AtomicExpr::AO__scoped_atomic_xor_fetch:
912 case AtomicExpr::AO__c11_atomic_fetch_xor:
913 case AtomicExpr::AO__atomic_fetch_xor:
914 case AtomicExpr::AO__scoped_atomic_fetch_xor:
915 case AtomicExpr::AO__hip_atomic_fetch_xor:
916 case AtomicExpr::AO__opencl_atomic_fetch_xor:
917 handleFetchOp(cir::AtomicFetchKind::Xor);
920 case AtomicExpr::AO__atomic_nand_fetch:
921 case AtomicExpr::AO__scoped_atomic_nand_fetch:
924 case AtomicExpr::AO__c11_atomic_fetch_nand:
925 case AtomicExpr::AO__atomic_fetch_nand:
926 case AtomicExpr::AO__scoped_atomic_fetch_nand:
927 handleFetchOp(cir::AtomicFetchKind::Nand);
930 case AtomicExpr::AO__atomic_test_and_set: {
931 auto op = cir::AtomicTestAndSetOp::create(
939 case AtomicExpr::AO__atomic_clear: {
940 cir::AtomicClearOp::create(
947 case AtomicExpr::AO__atomic_fetch_uinc:
948 case AtomicExpr::AO__scoped_atomic_fetch_uinc:
949 handleFetchOp(cir::AtomicFetchKind::UIncWrap);
952 case AtomicExpr::AO__atomic_fetch_udec:
953 case AtomicExpr::AO__scoped_atomic_fetch_udec:
954 handleFetchOp(cir::AtomicFetchKind::UDecWrap);
957 case AtomicExpr::AO__opencl_atomic_init:
962 assert(!opName.empty() &&
"expected operation name to build");
963 mlir::Value loadVal1 = builder.
createLoad(loc, val1);
967 mlir::Operation *rmwOp = builder.create(loc, builder.getStringAttr(opName),
968 atomicOperands, atomicResTys);
971 rmwOp->setAttr(
"binop", fetchAttr);
972 rmwOp->setAttr(
"mem_order", orderAttr);
973 rmwOp->setAttr(
"sync_scope", scopeAttr);
974 if (
expr->isVolatile())
975 rmwOp->setAttr(
"is_volatile", builder.getUnitAttr());
976 if (fetchFirst && opName == cir::AtomicFetchOp::getOperationName())
977 rmwOp->setAttr(
"fetch_first", builder.getUnitAttr());
981 mlir::Value result = rmwOp->getResult(0);
992 return cir::SyncScopeKind::SingleThread;
994 return cir::SyncScopeKind::System;
996 return cir::SyncScopeKind::Device;
998 return cir::SyncScopeKind::Workgroup;
1000 return cir::SyncScopeKind::Wavefront;
1002 return cir::SyncScopeKind::Cluster;
1005 return cir::SyncScopeKind::HIPSingleThread;
1007 return cir::SyncScopeKind::HIPSystem;
1009 return cir::SyncScopeKind::HIPAgent;
1011 return cir::SyncScopeKind::HIPWorkgroup;
1013 return cir::SyncScopeKind::HIPWavefront;
1015 return cir::SyncScopeKind::HIPCluster;
1018 return cir::SyncScopeKind::OpenCLWorkGroup;
1020 return cir::SyncScopeKind::OpenCLDevice;
1022 return cir::SyncScopeKind::OpenCLAllSVMDevices;
1024 return cir::SyncScopeKind::OpenCLSubGroup;
1027 llvm_unreachable(
"unhandled sync scope");
1034 cir::MemOrder order,
1035 const std::optional<Expr::EvalResult> &scopeConst,
1036 mlir::Value scopeValue) {
1037 std::unique_ptr<AtomicScopeModel> scopeModel =
expr->getScopeModel();
1041 failureOrderExpr, size, order, cir::SyncScopeKind::System);
1045 if (scopeConst.has_value()) {
1047 cgf,
expr->getScope()->getSourceRange(),
1048 scopeModel->map(scopeConst->Val.getInt().getZExtValue()));
1050 failureOrderExpr, size, order, mappedScope);
1057 mlir::Location loc = cgf.
getLoc(
expr->getSourceRange());
1059 unsigned fallback = scopeModel->getFallBackValue();
1061 cir::SwitchOp::create(
1062 builder, loc, scopeValue,
1063 [&](mlir::OpBuilder &, mlir::Location loc, mlir::OperationState &) {
1064 mlir::Block *switchBlock = builder.getBlock();
1068 cgf,
expr->getScope()->getSourceRange(), scopeModel->map(fallback));
1071 isWeakExpr, failureOrderExpr, size, order, fallbackScope);
1073 builder.setInsertionPointToEnd(switchBlock);
1076 for (
unsigned scope : allScopes) {
1077 if (scope == fallback)
1081 cgf,
expr->getScope()->getSourceRange(), scopeModel->map(scope));
1083 mlir::ArrayAttr casesAttr = builder.getArrayAttr(
1084 {cir::IntAttr::get(scopeValue.getType(), scope)});
1085 mlir::OpBuilder::InsertPoint insertPoint;
1086 cir::CaseOp::create(builder, loc, casesAttr, cir::CaseOpKind::Equal,
1089 builder.restoreInsertionPoint(insertPoint);
1091 isWeakExpr, failureOrderExpr, size, order, cirScope);
1093 builder.setInsertionPointToEnd(switchBlock);
1100static std::optional<cir::MemOrder>
1110 if (oriOrder == cir::MemOrder::Consume ||
1111 oriOrder == cir::MemOrder::Acquire ||
1112 oriOrder == cir::MemOrder::AcquireRelease)
1113 return std::nullopt;
1114 }
else if (isLoad) {
1115 if (oriOrder == cir::MemOrder::Release ||
1116 oriOrder == cir::MemOrder::AcquireRelease)
1117 return std::nullopt;
1118 }
else if (isFence) {
1119 if (oriOrder == cir::MemOrder::Relaxed)
1120 return std::nullopt;
1124 if (oriOrder == cir::MemOrder::Consume)
1125 return cir::MemOrder::Acquire;
1130 CIRGenFunction &cgf, mlir::Value order,
bool isStore,
bool isLoad,
1131 bool isFence, llvm::function_ref<
void(cir::MemOrder)> emitAtomicOpFn) {
1139 cir::SwitchOp::create(
1140 builder, order.getLoc(), order,
1141 [&](mlir::OpBuilder &, mlir::Location loc, mlir::OperationState &) {
1142 mlir::Block *switchBlock = builder.getBlock();
1144 auto emitMemOrderCase = [&](llvm::ArrayRef<cir::MemOrder> caseOrders) {
1146 for (int i = 1, e = caseOrders.size(); i < e; i++)
1147 assert((getEffectiveAtomicMemOrder(caseOrders[i - 1], isStore,
1149 getEffectiveAtomicMemOrder(caseOrders[i], isStore, isLoad,
1151 "Effective memory order must be same!");
1153 if (caseOrders.empty()) {
1154 emitDefaultCaseLabel(builder, loc);
1158 emitAtomicOpFn(cir::MemOrder::Relaxed);
1159 } else if (std::optional<cir::MemOrder> actualOrder =
1160 getEffectiveAtomicMemOrder(caseOrders[0], isStore,
1163 if (!isFence && actualOrder == cir::MemOrder::Relaxed)
1168 emitMemOrderCaseLabel(builder, loc, order.getType(), caseOrders);
1169 emitAtomicOpFn(actualOrder.value());
1174 builder.createBreak(loc);
1175 builder.setInsertionPointToEnd(switchBlock);
1178 emitMemOrderCase( {});
1179 emitMemOrderCase({cir::MemOrder::Relaxed});
1180 emitMemOrderCase({cir::MemOrder::Consume, cir::MemOrder::Acquire});
1181 emitMemOrderCase({cir::MemOrder::Release});
1182 emitMemOrderCase({cir::MemOrder::AcquireRelease});
1183 emitMemOrderCase({cir::MemOrder::SequentiallyConsistent});
1190 const Expr *memOrder,
bool isStore,
bool isLoad,
bool isFence,
1191 llvm::function_ref<
void(cir::MemOrder)> emitAtomicOpFn) {
1195 uint64_t constOrder = eval.
Val.
getInt().getZExtValue();
1200 cir::MemOrder oriOrder =
static_cast<cir::MemOrder
>(constOrder);
1201 if (std::optional<cir::MemOrder> actualOrder =
1203 emitAtomicOpFn(actualOrder.value());
1220 mlir::NamedAttrList fnAttrs;
1232 uint64_t atomicTySize,
1245 auto castToGenericAddrSpace = [&](mlir::Value v,
QualType pt) {
1250 cgf.
cgm.
errorNYI(loc,
"emitLibCallForAtomicExpr: openCL");
1260 llvm::StringRef calleeName;
1262 bool hasRetTy =
false;
1263 switch (e->
getOp()) {
1264 case AtomicExpr::AO__c11_atomic_init:
1265 case AtomicExpr::AO__opencl_atomic_init:
1266 llvm_unreachable(
"Already handled!");
1273 case AtomicExpr::AO__atomic_compare_exchange:
1274 case AtomicExpr::AO__atomic_compare_exchange_n:
1275 case AtomicExpr::AO__c11_atomic_compare_exchange_weak:
1276 case AtomicExpr::AO__c11_atomic_compare_exchange_strong:
1277 case AtomicExpr::AO__hip_atomic_compare_exchange_weak:
1278 case AtomicExpr::AO__hip_atomic_compare_exchange_strong:
1279 case AtomicExpr::AO__opencl_atomic_compare_exchange_weak:
1280 case AtomicExpr::AO__opencl_atomic_compare_exchange_strong:
1281 case AtomicExpr::AO__scoped_atomic_compare_exchange:
1282 case AtomicExpr::AO__scoped_atomic_compare_exchange_n: {
1283 calleeName =
"__atomic_compare_exchange";
1300 case AtomicExpr::AO__atomic_exchange:
1301 case AtomicExpr::AO__atomic_exchange_n:
1302 case AtomicExpr::AO__c11_atomic_exchange:
1303 case AtomicExpr::AO__hip_atomic_exchange:
1304 case AtomicExpr::AO__opencl_atomic_exchange:
1305 case AtomicExpr::AO__scoped_atomic_exchange:
1306 case AtomicExpr::AO__scoped_atomic_exchange_n:
1307 calleeName =
"__atomic_exchange";
1314 case AtomicExpr::AO__atomic_store:
1315 case AtomicExpr::AO__atomic_store_n:
1316 case AtomicExpr::AO__c11_atomic_store:
1317 case AtomicExpr::AO__hip_atomic_store:
1318 case AtomicExpr::AO__opencl_atomic_store:
1319 case AtomicExpr::AO__scoped_atomic_store:
1320 case AtomicExpr::AO__scoped_atomic_store_n:
1321 calleeName =
"__atomic_store";
1330 case AtomicExpr::AO__atomic_load:
1331 case AtomicExpr::AO__atomic_load_n:
1332 case AtomicExpr::AO__c11_atomic_load:
1333 case AtomicExpr::AO__hip_atomic_load:
1334 case AtomicExpr::AO__opencl_atomic_load:
1335 case AtomicExpr::AO__scoped_atomic_load:
1336 case AtomicExpr::AO__scoped_atomic_load_n:
1337 calleeName =
"__atomic_load";
1340 case AtomicExpr::AO__atomic_add_fetch:
1341 case AtomicExpr::AO__scoped_atomic_add_fetch:
1342 case AtomicExpr::AO__atomic_fetch_add:
1343 case AtomicExpr::AO__c11_atomic_fetch_add:
1344 case AtomicExpr::AO__hip_atomic_fetch_add:
1345 case AtomicExpr::AO__opencl_atomic_fetch_add:
1346 case AtomicExpr::AO__scoped_atomic_fetch_add:
1347 case AtomicExpr::AO__atomic_and_fetch:
1348 case AtomicExpr::AO__scoped_atomic_and_fetch:
1349 case AtomicExpr::AO__atomic_fetch_and:
1350 case AtomicExpr::AO__c11_atomic_fetch_and:
1351 case AtomicExpr::AO__hip_atomic_fetch_and:
1352 case AtomicExpr::AO__opencl_atomic_fetch_and:
1353 case AtomicExpr::AO__scoped_atomic_fetch_and:
1354 case AtomicExpr::AO__atomic_or_fetch:
1355 case AtomicExpr::AO__scoped_atomic_or_fetch:
1356 case AtomicExpr::AO__atomic_fetch_or:
1357 case AtomicExpr::AO__c11_atomic_fetch_or:
1358 case AtomicExpr::AO__hip_atomic_fetch_or:
1359 case AtomicExpr::AO__opencl_atomic_fetch_or:
1360 case AtomicExpr::AO__scoped_atomic_fetch_or:
1361 case AtomicExpr::AO__atomic_sub_fetch:
1362 case AtomicExpr::AO__scoped_atomic_sub_fetch:
1363 case AtomicExpr::AO__atomic_fetch_sub:
1364 case AtomicExpr::AO__c11_atomic_fetch_sub:
1365 case AtomicExpr::AO__hip_atomic_fetch_sub:
1366 case AtomicExpr::AO__opencl_atomic_fetch_sub:
1367 case AtomicExpr::AO__scoped_atomic_fetch_sub:
1368 case AtomicExpr::AO__atomic_xor_fetch:
1369 case AtomicExpr::AO__scoped_atomic_xor_fetch:
1370 case AtomicExpr::AO__atomic_fetch_xor:
1371 case AtomicExpr::AO__c11_atomic_fetch_xor:
1372 case AtomicExpr::AO__hip_atomic_fetch_xor:
1373 case AtomicExpr::AO__opencl_atomic_fetch_xor:
1374 case AtomicExpr::AO__scoped_atomic_fetch_xor:
1375 case AtomicExpr::AO__atomic_nand_fetch:
1376 case AtomicExpr::AO__atomic_fetch_nand:
1377 case AtomicExpr::AO__c11_atomic_fetch_nand:
1378 case AtomicExpr::AO__scoped_atomic_fetch_nand:
1379 case AtomicExpr::AO__scoped_atomic_nand_fetch:
1380 case AtomicExpr::AO__atomic_min_fetch:
1381 case AtomicExpr::AO__atomic_fetch_min:
1382 case AtomicExpr::AO__c11_atomic_fetch_min:
1383 case AtomicExpr::AO__hip_atomic_fetch_min:
1384 case AtomicExpr::AO__opencl_atomic_fetch_min:
1385 case AtomicExpr::AO__scoped_atomic_fetch_min:
1386 case AtomicExpr::AO__scoped_atomic_min_fetch:
1387 case AtomicExpr::AO__atomic_max_fetch:
1388 case AtomicExpr::AO__atomic_fetch_max:
1389 case AtomicExpr::AO__c11_atomic_fetch_max:
1390 case AtomicExpr::AO__hip_atomic_fetch_max:
1391 case AtomicExpr::AO__opencl_atomic_fetch_max:
1392 case AtomicExpr::AO__scoped_atomic_fetch_max:
1393 case AtomicExpr::AO__scoped_atomic_max_fetch:
1394 case AtomicExpr::AO__scoped_atomic_fetch_uinc:
1395 case AtomicExpr::AO__scoped_atomic_fetch_udec:
1396 case AtomicExpr::AO__atomic_fetch_fmaximum:
1397 case AtomicExpr::AO__atomic_fetch_fmaximum_num:
1398 case AtomicExpr::AO__atomic_fetch_fminimum:
1399 case AtomicExpr::AO__atomic_fetch_fminimum_num:
1400 case AtomicExpr::AO__scoped_atomic_fetch_fmaximum:
1401 case AtomicExpr::AO__scoped_atomic_fetch_fmaximum_num:
1402 case AtomicExpr::AO__scoped_atomic_fetch_fminimum:
1403 case AtomicExpr::AO__scoped_atomic_fetch_fminimum_num:
1404 case AtomicExpr::AO__atomic_test_and_set:
1405 case AtomicExpr::AO__atomic_clear:
1406 case AtomicExpr::AO__atomic_fetch_uinc:
1407 case AtomicExpr::AO__atomic_fetch_udec:
1408 llvm_unreachable(
"Integral atomic operations always become atomicrmw!");
1413 cgf.
cgm.
errorNYI(loc,
"emitLibCallForAtomicExpr: openCL");
1429 cgf.
cgm.
errorNYI(loc,
"emitLibCallForAtomicExpr: openCL");
1451 memTy = ty->getValueType();
1453 Expr *isWeakExpr =
nullptr;
1454 Expr *orderFailExpr =
nullptr;
1462 if (e->
getOp() == AtomicExpr::AO__c11_atomic_init) {
1474 std::optional<Expr::EvalResult> scopeConst;
1477 scopeConst.emplace(std::move(eval));
1479 switch (e->
getOp()) {
1484 case AtomicExpr::AO__c11_atomic_init:
1485 llvm_unreachable(
"already handled above with emitAtomicInit");
1487 case AtomicExpr::AO__atomic_load_n:
1488 case AtomicExpr::AO__scoped_atomic_load_n:
1489 case AtomicExpr::AO__c11_atomic_load:
1490 case AtomicExpr::AO__opencl_atomic_load:
1491 case AtomicExpr::AO__hip_atomic_load:
1492 case AtomicExpr::AO__atomic_test_and_set:
1493 case AtomicExpr::AO__atomic_clear:
1496 case AtomicExpr::AO__atomic_load:
1497 case AtomicExpr::AO__scoped_atomic_load:
1501 case AtomicExpr::AO__atomic_store:
1502 case AtomicExpr::AO__scoped_atomic_store:
1506 case AtomicExpr::AO__atomic_exchange:
1507 case AtomicExpr::AO__scoped_atomic_exchange:
1512 case AtomicExpr::AO__atomic_compare_exchange:
1513 case AtomicExpr::AO__atomic_compare_exchange_n:
1514 case AtomicExpr::AO__c11_atomic_compare_exchange_weak:
1515 case AtomicExpr::AO__c11_atomic_compare_exchange_strong:
1516 case AtomicExpr::AO__scoped_atomic_compare_exchange:
1517 case AtomicExpr::AO__scoped_atomic_compare_exchange_n:
1518 case AtomicExpr::AO__hip_atomic_compare_exchange_strong:
1519 case AtomicExpr::AO__hip_atomic_compare_exchange_weak:
1520 case AtomicExpr::AO__opencl_atomic_compare_exchange_strong:
1521 case AtomicExpr::AO__opencl_atomic_compare_exchange_weak:
1523 if (e->
getOp() == AtomicExpr::AO__atomic_compare_exchange ||
1524 e->
getOp() == AtomicExpr::AO__scoped_atomic_compare_exchange)
1529 if (e->
getOp() == AtomicExpr::AO__atomic_compare_exchange_n ||
1530 e->
getOp() == AtomicExpr::AO__atomic_compare_exchange ||
1531 e->
getOp() == AtomicExpr::AO__scoped_atomic_compare_exchange_n ||
1532 e->
getOp() == AtomicExpr::AO__scoped_atomic_compare_exchange)
1536 case AtomicExpr::AO__c11_atomic_fetch_add:
1537 case AtomicExpr::AO__c11_atomic_fetch_sub:
1548 mlir::Value scale = builder.getConstInt(loc, val1Scalar.getType(),
1550 val1Scalar = builder.createMul(loc, val1Scalar, scale);
1556 case AtomicExpr::AO__atomic_fetch_add:
1557 case AtomicExpr::AO__atomic_fetch_sub:
1558 case AtomicExpr::AO__atomic_add_fetch:
1559 case AtomicExpr::AO__atomic_sub_fetch:
1569 case AtomicExpr::AO__atomic_fetch_max:
1570 case AtomicExpr::AO__atomic_fetch_min:
1571 case AtomicExpr::AO__atomic_max_fetch:
1572 case AtomicExpr::AO__atomic_min_fetch:
1573 case AtomicExpr::AO__c11_atomic_fetch_max:
1574 case AtomicExpr::AO__c11_atomic_fetch_min:
1575 case AtomicExpr::AO__scoped_atomic_fetch_add:
1576 case AtomicExpr::AO__scoped_atomic_fetch_max:
1577 case AtomicExpr::AO__scoped_atomic_fetch_min:
1578 case AtomicExpr::AO__scoped_atomic_fetch_sub:
1579 case AtomicExpr::AO__scoped_atomic_fetch_fminimum:
1580 case AtomicExpr::AO__scoped_atomic_fetch_fmaximum:
1581 case AtomicExpr::AO__scoped_atomic_fetch_fminimum_num:
1582 case AtomicExpr::AO__scoped_atomic_fetch_fmaximum_num:
1583 case AtomicExpr::AO__scoped_atomic_add_fetch:
1584 case AtomicExpr::AO__scoped_atomic_max_fetch:
1585 case AtomicExpr::AO__scoped_atomic_min_fetch:
1586 case AtomicExpr::AO__scoped_atomic_sub_fetch:
1589 case AtomicExpr::AO__atomic_fetch_and:
1590 case AtomicExpr::AO__atomic_fetch_nand:
1591 case AtomicExpr::AO__atomic_fetch_or:
1592 case AtomicExpr::AO__atomic_fetch_xor:
1593 case AtomicExpr::AO__atomic_and_fetch:
1594 case AtomicExpr::AO__atomic_nand_fetch:
1595 case AtomicExpr::AO__atomic_or_fetch:
1596 case AtomicExpr::AO__atomic_xor_fetch:
1597 case AtomicExpr::AO__atomic_exchange_n:
1598 case AtomicExpr::AO__atomic_store_n:
1599 case AtomicExpr::AO__c11_atomic_fetch_and:
1600 case AtomicExpr::AO__c11_atomic_fetch_nand:
1601 case AtomicExpr::AO__c11_atomic_fetch_or:
1602 case AtomicExpr::AO__c11_atomic_fetch_xor:
1603 case AtomicExpr::AO__c11_atomic_exchange:
1604 case AtomicExpr::AO__c11_atomic_store:
1605 case AtomicExpr::AO__scoped_atomic_fetch_and:
1606 case AtomicExpr::AO__scoped_atomic_fetch_nand:
1607 case AtomicExpr::AO__scoped_atomic_fetch_or:
1608 case AtomicExpr::AO__scoped_atomic_fetch_xor:
1609 case AtomicExpr::AO__scoped_atomic_and_fetch:
1610 case AtomicExpr::AO__scoped_atomic_nand_fetch:
1611 case AtomicExpr::AO__scoped_atomic_or_fetch:
1612 case AtomicExpr::AO__scoped_atomic_xor_fetch:
1613 case AtomicExpr::AO__scoped_atomic_store_n:
1614 case AtomicExpr::AO__scoped_atomic_exchange_n:
1615 case AtomicExpr::AO__atomic_fetch_uinc:
1616 case AtomicExpr::AO__atomic_fetch_udec:
1617 case AtomicExpr::AO__scoped_atomic_fetch_uinc:
1618 case AtomicExpr::AO__scoped_atomic_fetch_udec:
1619 case AtomicExpr::AO__atomic_fetch_fminimum:
1620 case AtomicExpr::AO__atomic_fetch_fmaximum:
1621 case AtomicExpr::AO__atomic_fetch_fminimum_num:
1622 case AtomicExpr::AO__atomic_fetch_fmaximum_num:
1623 case AtomicExpr::AO__hip_atomic_exchange:
1624 case AtomicExpr::AO__hip_atomic_store:
1625 case AtomicExpr::AO__hip_atomic_fetch_add:
1626 case AtomicExpr::AO__hip_atomic_fetch_sub:
1627 case AtomicExpr::AO__hip_atomic_fetch_min:
1628 case AtomicExpr::AO__hip_atomic_fetch_max:
1629 case AtomicExpr::AO__hip_atomic_fetch_and:
1630 case AtomicExpr::AO__hip_atomic_fetch_or:
1631 case AtomicExpr::AO__hip_atomic_fetch_xor:
1632 case AtomicExpr::AO__opencl_atomic_exchange:
1633 case AtomicExpr::AO__opencl_atomic_store:
1634 case AtomicExpr::AO__opencl_atomic_fetch_add:
1635 case AtomicExpr::AO__opencl_atomic_fetch_sub:
1636 case AtomicExpr::AO__opencl_atomic_fetch_min:
1637 case AtomicExpr::AO__opencl_atomic_fetch_max:
1638 case AtomicExpr::AO__opencl_atomic_fetch_and:
1639 case AtomicExpr::AO__opencl_atomic_fetch_or:
1640 case AtomicExpr::AO__opencl_atomic_fetch_xor:
1647 bool shouldCastToIntPtrTy =
1655 AtomicInfo atomics(*
this, atomicValue, loc);
1661 if (shouldCastToIntPtrTy) {
1662 ptr = atomics.castToAtomicIntPointer(ptr);
1664 val1 = atomics.convertToAtomicIntPointer(val1, loc);
1666 val2 = atomics.convertToAtomicIntPointer(val2, loc);
1669 if (shouldCastToIntPtrTy)
1670 dest = atomics.castToAtomicIntPointer(dest);
1673 }
else if (e->
getOp() == AtomicExpr::AO__atomic_test_and_set) {
1676 dest = atomics.createTempAlloca();
1677 if (shouldCastToIntPtrTy)
1678 dest = atomics.castToAtomicIntPointer(dest);
1681 bool powerOf2Size = (size & (size - 1)) == 0;
1682 bool useLibCall = !powerOf2Size || (size > 16);
1697 bool isStore = e->
getOp() == AtomicExpr::AO__c11_atomic_store ||
1698 e->
getOp() == AtomicExpr::AO__opencl_atomic_store ||
1699 e->
getOp() == AtomicExpr::AO__hip_atomic_store ||
1700 e->
getOp() == AtomicExpr::AO__atomic_store ||
1701 e->
getOp() == AtomicExpr::AO__atomic_store_n ||
1702 e->
getOp() == AtomicExpr::AO__scoped_atomic_store ||
1703 e->
getOp() == AtomicExpr::AO__scoped_atomic_store_n ||
1704 e->
getOp() == AtomicExpr::AO__atomic_clear;
1705 bool isLoad = e->
getOp() == AtomicExpr::AO__c11_atomic_load ||
1706 e->
getOp() == AtomicExpr::AO__opencl_atomic_load ||
1707 e->
getOp() == AtomicExpr::AO__hip_atomic_load ||
1708 e->
getOp() == AtomicExpr::AO__atomic_load ||
1709 e->
getOp() == AtomicExpr::AO__atomic_load_n ||
1710 e->
getOp() == AtomicExpr::AO__scoped_atomic_load ||
1711 e->
getOp() == AtomicExpr::AO__scoped_atomic_load_n;
1713 auto emitAtomicOpCallBackFn = [&](cir::MemOrder memOrder) {
1714 emitAtomicOp(*
this, e, dest, ptr, val1, val2, originalVal1, isWeakExpr,
1715 orderFailExpr, size, memOrder, scopeConst, scope);
1718 emitAtomicOpCallBackFn);
1731 return emitAtomicLoad(lvalue, loc, cir::MemOrder::SequentiallyConsistent,
1738 cir::MemOrder order,
bool isVolatile,
1740 AtomicInfo info(*
this, lvalue,
getLoc(loc));
1741 return info.emitAtomicLoad(slot, loc,
true, order, isVolatile);
1746 auto order = cir::MemOrder::SequentiallyConsistent;
1759 cir::MemOrder order,
bool isVolatile,
1763 mlir::Location loc = dest.
getPointer().getLoc();
1768 AtomicInfo atomics(*
this, dest, loc);
1769 LValue lvalue = atomics.getAtomicLValue();
1774 atomics.emitCopyIntoMemory(rvalue);
1779 if (atomics.shouldUseLibCall()) {
1781 cgm.errorNYI(loc,
"emitAtomicStore: atomic store with library call");
1786 mlir::Value valueToStore = atomics.convertRValueToInt(rvalue, loc);
1789 Address addr = atomics.getAtomicAddress();
1790 if (mlir::Value value = atomics.getScalarRValValueOrNull(rvalue)) {
1792 addr = atomics.castToAtomicIntPointer(addr);
1797 cir::StoreOp store = builder.createStore(loc, valueToStore, addr);
1802 store.setMemOrder(order);
1807 store.setIsVolatile(
true);
1813 cgm.errorNYI(loc,
"emitAtomicStore: non-simple atomic lvalue");
1820 switch (atomics.getEvaluationKind()) {
1836 bool zeroed =
false;
1838 zeroed = atomics.emitMemSetZeroIfNecessary();
1839 dest = atomics.projectValue();
1854 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.
__builtin_bitreverse32 uint32_t __builtin_riscv_aaddu_u32 __builtin_riscv_asubu_u32 __builtin_elementwise_add_sat __builtin_elementwise_sub_sat int32_t uint32_t uint32_t __builtin_riscv_mhacc_i32 __builtin_riscv_mhaccu_u32 __builtin_riscv_mhaccsu_i32 __builtin_riscv_mulq_i32 int64_t
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.