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);
174 uint64_t expectedSize) {
181bool AtomicInfo::requiresMemSetZero(mlir::Type ty)
const {
187 switch (getEvaluationKind()) {
194 mlir::cast<cir::ComplexType>(ty).getElementType(),
195 atomicSizeInBits / 2);
200 llvm_unreachable(
"bad evaluation kind");
203Address AtomicInfo::convertToAtomicIntPointer(Address addr,
204 mlir::Location loc)
const {
207 if (sourceSizeInBits != atomicSizeInBits) {
210 Address tmp = createTempAlloca();
222 std::min(atomicSizeInBits, sourceSizeInBits) / 8));
226 return castToAtomicIntPointer(addr);
229RValue AtomicInfo::convertAtomicTempToRValue(Address addr,
230 AggValueSlot resultSlot,
232 bool asValue)
const {
233 if (lvalue.isSimple()) {
240 "AtomicInfo::convertAtomicTempToRValue: hasPadding");
250 loc,
"AtomicInfo::convertAtomicTempToRValue: lvalue is not simple");
254RValue AtomicInfo::emitAtomicLoad(AggValueSlot resultSlot, SourceLocation loc,
255 bool asValue, cir::MemOrder order,
258 if (shouldUseLibCall()) {
260 cgf.
cgm.
errorNYI(loc,
"emitAtomicLoad: emit atomic lib call");
265 mlir::Value loadOp = emitAtomicLoadOp(order, isVolatile);
273 return convertToValueOrAtomic(loadOp, resultSlot, loc, asValue);
276Address AtomicInfo::createTempAlloca()
const {
279 QualType tmpTy = (lvalue.isBitField() && valueSizeInBits > atomicSizeInBits)
283 cgf.
createMemTemp(tmpTy, getAtomicAlignment(), loc,
"atomic-temp");
286 if (lvalue.isBitField()) {
287 cgf.
cgm.
errorNYI(loc,
"AtomicInfo::createTempAlloca: bitfield lvalue");
293mlir::Value AtomicInfo::getScalarRValValueOrNull(RValue rvalue)
const {
294 if (rvalue.
isScalar() && (!hasPadding() || !lvalue.isSimple()))
299Address AtomicInfo::castToAtomicIntPointer(Address addr)
const {
302 if (intTy && intTy.getWidth() == atomicSizeInBits)
308bool AtomicInfo::emitMemSetZeroIfNecessary()
const {
309 assert(lvalue.isSimple());
310 Address addr = lvalue.getAddress();
330 if (cir::isAnyFloatingPointType(valueTy))
335mlir::Value AtomicInfo::emitAtomicLoadOp(cir::MemOrder order,
bool isVolatile,
337 Address addr = getAtomicAddress();
339 addr = castToAtomicIntPointer(addr);
343 op.setMemOrder(order);
349mlir::Value AtomicInfo::convertRValueToInt(RValue rvalue, mlir::Location loc,
350 bool cmpxchg)
const {
353 if (mlir::Value value = getScalarRValValueOrNull(rvalue)) {
358 loc,
"AtomicInfo::convertRValueToInt: cast scalar rvalue to int");
364 Address addr = materializeRValue(rvalue, loc);
367 addr = castToAtomicIntPointer(addr);
372RValue AtomicInfo::convertToValueOrAtomic(mlir::Value intVal,
373 AggValueSlot resultSlot,
374 SourceLocation loc,
bool asValue,
375 bool cmpxchg)
const {
377 assert((mlir::isa<cir::IntType, cir::PointerType, cir::FPTypeInterface>(
378 intVal.getType())) &&
379 "Expected integer, pointer or floating point value when converting "
382 !lvalue.isBitField() || lvalue.getBitFieldInfo().size == valueSizeInBits;
384 ((isWholeValue && !hasPadding()) || !asValue)) {
386 : getAtomicAddress().getElementType();
388 assert((!mlir::isa<cir::IntType>(valTy) || intVal.getType() == valTy) &&
389 "Different integer types.");
393 cgf.
cgm.
errorNYI(
"convertToValueOrAtomic: convert through bitcast");
400 bool tempIsVolatile =
false;
406 temp = createTempAlloca();
410 Address castTemp = castToAtomicIntPointer(temp);
413 return convertAtomicTempToRValue(temp, resultSlot, loc, asValue);
418void AtomicInfo::emitCopyIntoMemory(RValue rvalue)
const {
419 assert(lvalue.isSimple());
425 cgf.
cgm.
errorNYI(
"copying aggregate into atomic lvalue");
432 emitMemSetZeroIfNecessary();
435 LValue tempLValue = projectValue();
448Address AtomicInfo::materializeRValue(RValue rvalue, mlir::Location loc)
const {
455 LValue tempLV = cgf.
makeAddrLValue(createTempAlloca(), getAtomicType());
456 AtomicInfo atomics(cgf, tempLV, loc);
458 atomics.emitCopyIntoMemory(rvalue);
459 return tempLV.getAddress();
463 mlir::ArrayAttr valuesAttr = builder.getArrayAttr({});
464 mlir::OpBuilder::InsertPoint insertPoint;
465 cir::CaseOp::create(builder, loc, valuesAttr, cir::CaseOpKind::Default,
467 builder.restoreInsertionPoint(insertPoint);
473 mlir::Type orderType,
476 for (cir::MemOrder order : orders)
477 orderAttrs.push_back(cir::IntAttr::get(orderType,
static_cast<int>(order)));
478 mlir::ArrayAttr ordersAttr = builder.getArrayAttr(orderAttrs);
480 mlir::OpBuilder::InsertPoint insertPoint;
481 cir::CaseOp::create(builder, loc, ordersAttr, cir::CaseOpKind::Anyof,
483 builder.restoreInsertionPoint(insertPoint);
489 uint64_t size, cir::MemOrder successOrder,
490 cir::MemOrder failureOrder,
491 cir::SyncScopeKind scope) {
495 mlir::Value expected = builder.
createLoad(loc, val1);
496 mlir::Value desired = builder.
createLoad(loc, val2);
498 auto cmpxchg = cir::AtomicCmpXchgOp::create(
507 cmpxchg.setWeak(isWeak);
509 mlir::Value failed = builder.
createNot(cmpxchg.getSuccess());
511 builder, loc, failed,
false,
512 [&](mlir::OpBuilder &, mlir::Location) {
516 if (expectedSizeInBytes == size) {
518 builder, cmpxchg.getOld().getType());
519 builder.
createStore(loc, cmpxchg.getOld(), storeAddr);
523 cmpxchg.getOld().getType(), ptr.
getAlignment(), loc,
"old.tmp");
524 builder.
createStore(loc, cmpxchg.getOld(), oldTmp);
531 loc, expectedVoid, oldTmpVoid,
546 uint64_t size, cir::MemOrder successOrder, cir::SyncScopeKind scope) {
549 uint64_t failureOrderInt = failureOrderEval.
Val.
getInt().getZExtValue();
551 cir::MemOrder failureOrder;
553 failureOrder = cir::MemOrder::Relaxed;
555 switch ((cir::MemOrder)failureOrderInt) {
556 case cir::MemOrder::Relaxed:
559 case cir::MemOrder::Release:
560 case cir::MemOrder::AcquireRelease:
561 failureOrder = cir::MemOrder::Relaxed;
563 case cir::MemOrder::Consume:
564 case cir::MemOrder::Acquire:
565 failureOrder = cir::MemOrder::Acquire;
567 case cir::MemOrder::SequentiallyConsistent:
568 failureOrder = cir::MemOrder::SequentiallyConsistent;
578 size, successOrder, failureOrder, scope);
586 mlir::Value failureOrderVal = cgf.
emitScalarExpr(failureOrderExpr);
588 cir::SwitchOp::create(
590 [&](mlir::OpBuilder &b, mlir::Location loc, mlir::OperationState &os) {
591 mlir::Block *switchBlock = cgf.getBuilder().getBlock();
603 emitDefaultCaseLabel(cgf.getBuilder(), atomicLoc);
604 emitAtomicCmpXchg(cgf, e, isWeak, dest, ptr, val1, val2, expectedResult,
605 size, successOrder, cir::MemOrder::Relaxed, scope);
606 cgf.getBuilder().createBreak(atomicLoc);
607 cgf.getBuilder().setInsertionPointToEnd(switchBlock);
611 emitMemOrderCaseLabel(cgf.getBuilder(), loc, failureOrderVal.getType(),
612 {cir::MemOrder::Consume, cir::MemOrder::Acquire});
614 size, successOrder, cir::MemOrder::Acquire, scope);
616 cgf.
getBuilder().setInsertionPointToEnd(switchBlock);
620 {cir::MemOrder::SequentiallyConsistent});
623 cir::MemOrder::SequentiallyConsistent, scope);
625 cgf.
getBuilder().setInsertionPointToEnd(switchBlock);
637 Expr *failureOrderExpr, uint64_t size, cir::MemOrder successOrder,
638 cir::SyncScopeKind scope) {
650 [&](mlir::OpBuilder &b, mlir::Location loc) {
651 emitAtomicCmpXchgFailureSet(cgf, e, true, dest, ptr, val1,
652 val2, expectedResult, failureOrderExpr,
653 size, successOrder, scope);
654 cgf.getBuilder().createYield(atomicLoc);
656 [&](mlir::OpBuilder &b, mlir::Location loc) {
657 emitAtomicCmpXchgFailureSet(cgf, e, false, dest, ptr, val1,
658 val2, expectedResult, failureOrderExpr,
659 size, successOrder, scope);
660 cgf.getBuilder().createYield(atomicLoc);
682 auto fetchOp = mlir::dyn_cast<cir::AtomicFetchOp>(op);
687 mlir::UnitAttr unit = cgf.
getBuilder().getUnitAttr();
689 op->setAttr(cir::CIRDialect::getAMDGPUNoFineGrainedMemoryAttrName(), unit);
691 op->setAttr(cir::CIRDialect::getAMDGPUNoRemoteMemoryAttrName(), unit);
694 fetchOp.getBinop() == cir::AtomicFetchKind::Add &&
695 mlir::isa<cir::SingleType>(fetchOp.getVal().getType()))
696 op->setAttr(cir::CIRDialect::getAMDGPUIgnoreDenormalModeAttrName(), unit);
702 Expr *failureOrderExpr, int64_t size,
703 cir::MemOrder order, cir::SyncScopeKind scope) {
705 llvm::StringRef opName;
708 mlir::Location loc = cgf.
getLoc(
expr->getSourceRange());
709 auto orderAttr = cir::MemOrderAttr::get(builder.getContext(), order);
710 auto scopeAttr = cir::SyncScopeKindAttr::get(builder.getContext(), scope);
711 cir::AtomicFetchKindAttr fetchAttr;
712 bool fetchFirst =
true;
714 auto handleFetchOp = [&](cir::AtomicFetchKind
kind) {
715 opName = cir::AtomicFetchOp::getOperationName();
716 fetchAttr = cir::AtomicFetchKindAttr::get(builder.getContext(),
kind);
719 switch (
expr->getOp()) {
720 case AtomicExpr::AO__c11_atomic_init:
721 llvm_unreachable(
"already handled!");
723 case AtomicExpr::AO__c11_atomic_compare_exchange_strong:
724 case AtomicExpr::AO__hip_atomic_compare_exchange_strong:
725 case AtomicExpr::AO__opencl_atomic_compare_exchange_strong:
727 val2, expectedResult, failureOrderExpr, size,
731 case AtomicExpr::AO__c11_atomic_compare_exchange_weak:
732 case AtomicExpr::AO__hip_atomic_compare_exchange_weak:
733 case AtomicExpr::AO__opencl_atomic_compare_exchange_weak:
735 val2, expectedResult, failureOrderExpr, size,
739 case AtomicExpr::AO__atomic_compare_exchange:
740 case AtomicExpr::AO__atomic_compare_exchange_n:
741 case AtomicExpr::AO__scoped_atomic_compare_exchange:
742 case AtomicExpr::AO__scoped_atomic_compare_exchange_n: {
746 expectedResult, failureOrderExpr, size, order,
750 cgf,
expr, isWeakExpr, dest, ptr, val1, val2, expectedResult,
751 failureOrderExpr, size, order, scope);
756 case AtomicExpr::AO__c11_atomic_load:
757 case AtomicExpr::AO__atomic_load_n:
758 case AtomicExpr::AO__atomic_load:
759 case AtomicExpr::AO__scoped_atomic_load_n:
760 case AtomicExpr::AO__scoped_atomic_load:
761 case AtomicExpr::AO__hip_atomic_load:
762 case AtomicExpr::AO__opencl_atomic_load: {
766 load->setAttr(
"mem_order", orderAttr);
767 load->setAttr(
"sync_scope", scopeAttr);
769 builder.
createStore(loc, load->getResult(0), dest);
773 case AtomicExpr::AO__c11_atomic_store:
774 case AtomicExpr::AO__atomic_store_n:
775 case AtomicExpr::AO__atomic_store:
776 case AtomicExpr::AO__scoped_atomic_store:
777 case AtomicExpr::AO__scoped_atomic_store_n:
778 case AtomicExpr::AO__hip_atomic_store:
779 case AtomicExpr::AO__opencl_atomic_store: {
780 cir::LoadOp loadVal1 = builder.
createLoad(loc, val1);
786 mlir::IntegerAttr{}, scopeAttr, orderAttr);
790 case AtomicExpr::AO__c11_atomic_exchange:
791 case AtomicExpr::AO__atomic_exchange_n:
792 case AtomicExpr::AO__atomic_exchange:
793 case AtomicExpr::AO__scoped_atomic_exchange_n:
794 case AtomicExpr::AO__scoped_atomic_exchange:
795 case AtomicExpr::AO__hip_atomic_exchange:
796 case AtomicExpr::AO__opencl_atomic_exchange:
797 opName = cir::AtomicXchgOp::getOperationName();
800 case AtomicExpr::AO__atomic_add_fetch:
801 case AtomicExpr::AO__scoped_atomic_add_fetch:
804 case AtomicExpr::AO__c11_atomic_fetch_add:
805 case AtomicExpr::AO__atomic_fetch_add:
806 case AtomicExpr::AO__scoped_atomic_fetch_add:
807 case AtomicExpr::AO__hip_atomic_fetch_add:
808 case AtomicExpr::AO__opencl_atomic_fetch_add:
809 handleFetchOp(cir::AtomicFetchKind::Add);
812 case AtomicExpr::AO__atomic_sub_fetch:
813 case AtomicExpr::AO__scoped_atomic_sub_fetch:
816 case AtomicExpr::AO__c11_atomic_fetch_sub:
817 case AtomicExpr::AO__atomic_fetch_sub:
818 case AtomicExpr::AO__scoped_atomic_fetch_sub:
819 case AtomicExpr::AO__hip_atomic_fetch_sub:
820 case AtomicExpr::AO__opencl_atomic_fetch_sub:
821 handleFetchOp(cir::AtomicFetchKind::Sub);
824 case AtomicExpr::AO__atomic_min_fetch:
825 case AtomicExpr::AO__scoped_atomic_min_fetch:
828 case AtomicExpr::AO__c11_atomic_fetch_min:
829 case AtomicExpr::AO__atomic_fetch_min:
830 case AtomicExpr::AO__scoped_atomic_fetch_min:
831 case AtomicExpr::AO__hip_atomic_fetch_min:
832 case AtomicExpr::AO__opencl_atomic_fetch_min:
833 handleFetchOp(cir::AtomicFetchKind::Min);
836 case AtomicExpr::AO__atomic_fetch_fminimum:
837 case AtomicExpr::AO__scoped_atomic_fetch_fminimum:
838 assert(
expr->getValueType()->isFloatingType() &&
839 "fminimum operations only support floating-point types");
840 handleFetchOp(cir::AtomicFetchKind::Minimum);
843 case AtomicExpr::AO__atomic_fetch_fminimum_num:
844 case AtomicExpr::AO__scoped_atomic_fetch_fminimum_num:
845 assert(
expr->getValueType()->isFloatingType() &&
846 "fminimum_num operations only support floating-point types");
847 handleFetchOp(cir::AtomicFetchKind::MinimumNum);
850 case AtomicExpr::AO__atomic_max_fetch:
851 case AtomicExpr::AO__scoped_atomic_max_fetch:
854 case AtomicExpr::AO__c11_atomic_fetch_max:
855 case AtomicExpr::AO__atomic_fetch_max:
856 case AtomicExpr::AO__scoped_atomic_fetch_max:
857 case AtomicExpr::AO__hip_atomic_fetch_max:
858 case AtomicExpr::AO__opencl_atomic_fetch_max:
859 handleFetchOp(cir::AtomicFetchKind::Max);
862 case AtomicExpr::AO__atomic_fetch_fmaximum:
863 case AtomicExpr::AO__scoped_atomic_fetch_fmaximum:
864 assert(
expr->getValueType()->isFloatingType() &&
865 "fmaximum operations only support floating-point types");
866 handleFetchOp(cir::AtomicFetchKind::Maximum);
869 case AtomicExpr::AO__atomic_fetch_fmaximum_num:
870 case AtomicExpr::AO__scoped_atomic_fetch_fmaximum_num:
871 assert(
expr->getValueType()->isFloatingType() &&
872 "fmaximum_num operations only support floating-point types");
873 handleFetchOp(cir::AtomicFetchKind::MaximumNum);
876 case AtomicExpr::AO__atomic_and_fetch:
877 case AtomicExpr::AO__scoped_atomic_and_fetch:
880 case AtomicExpr::AO__c11_atomic_fetch_and:
881 case AtomicExpr::AO__atomic_fetch_and:
882 case AtomicExpr::AO__scoped_atomic_fetch_and:
883 case AtomicExpr::AO__hip_atomic_fetch_and:
884 case AtomicExpr::AO__opencl_atomic_fetch_and:
885 handleFetchOp(cir::AtomicFetchKind::And);
888 case AtomicExpr::AO__atomic_or_fetch:
889 case AtomicExpr::AO__scoped_atomic_or_fetch:
892 case AtomicExpr::AO__c11_atomic_fetch_or:
893 case AtomicExpr::AO__atomic_fetch_or:
894 case AtomicExpr::AO__scoped_atomic_fetch_or:
895 case AtomicExpr::AO__hip_atomic_fetch_or:
896 case AtomicExpr::AO__opencl_atomic_fetch_or:
897 handleFetchOp(cir::AtomicFetchKind::Or);
900 case AtomicExpr::AO__atomic_xor_fetch:
901 case AtomicExpr::AO__scoped_atomic_xor_fetch:
904 case AtomicExpr::AO__c11_atomic_fetch_xor:
905 case AtomicExpr::AO__atomic_fetch_xor:
906 case AtomicExpr::AO__scoped_atomic_fetch_xor:
907 case AtomicExpr::AO__hip_atomic_fetch_xor:
908 case AtomicExpr::AO__opencl_atomic_fetch_xor:
909 handleFetchOp(cir::AtomicFetchKind::Xor);
912 case AtomicExpr::AO__atomic_nand_fetch:
913 case AtomicExpr::AO__scoped_atomic_nand_fetch:
916 case AtomicExpr::AO__c11_atomic_fetch_nand:
917 case AtomicExpr::AO__atomic_fetch_nand:
918 case AtomicExpr::AO__scoped_atomic_fetch_nand:
919 handleFetchOp(cir::AtomicFetchKind::Nand);
922 case AtomicExpr::AO__atomic_test_and_set: {
923 auto op = cir::AtomicTestAndSetOp::create(
931 case AtomicExpr::AO__atomic_clear: {
932 cir::AtomicClearOp::create(
939 case AtomicExpr::AO__atomic_fetch_uinc:
940 case AtomicExpr::AO__scoped_atomic_fetch_uinc:
941 handleFetchOp(cir::AtomicFetchKind::UIncWrap);
944 case AtomicExpr::AO__atomic_fetch_udec:
945 case AtomicExpr::AO__scoped_atomic_fetch_udec:
946 handleFetchOp(cir::AtomicFetchKind::UDecWrap);
949 case AtomicExpr::AO__opencl_atomic_init:
954 assert(!opName.empty() &&
"expected operation name to build");
955 mlir::Value loadVal1 = builder.
createLoad(loc, val1);
959 mlir::Operation *rmwOp = builder.create(loc, builder.getStringAttr(opName),
960 atomicOperands, atomicResTys);
963 rmwOp->setAttr(
"binop", fetchAttr);
964 rmwOp->setAttr(
"mem_order", orderAttr);
965 rmwOp->setAttr(
"sync_scope", scopeAttr);
966 if (
expr->isVolatile())
967 rmwOp->setAttr(
"is_volatile", builder.getUnitAttr());
968 if (fetchFirst && opName == cir::AtomicFetchOp::getOperationName())
969 rmwOp->setAttr(
"fetch_first", builder.getUnitAttr());
974 mlir::Value result = rmwOp->getResult(0);
985 return cir::SyncScopeKind::SingleThread;
987 return cir::SyncScopeKind::System;
989 return cir::SyncScopeKind::Device;
991 return cir::SyncScopeKind::Workgroup;
993 return cir::SyncScopeKind::Wavefront;
995 return cir::SyncScopeKind::Cluster;
998 return cir::SyncScopeKind::HIPSingleThread;
1000 return cir::SyncScopeKind::HIPSystem;
1002 return cir::SyncScopeKind::HIPAgent;
1004 return cir::SyncScopeKind::HIPWorkgroup;
1006 return cir::SyncScopeKind::HIPWavefront;
1008 return cir::SyncScopeKind::HIPCluster;
1011 return cir::SyncScopeKind::OpenCLWorkGroup;
1013 return cir::SyncScopeKind::OpenCLDevice;
1015 return cir::SyncScopeKind::OpenCLAllSVMDevices;
1017 return cir::SyncScopeKind::OpenCLSubGroup;
1020 llvm_unreachable(
"unhandled sync scope");
1026 Expr *failureOrderExpr, int64_t size,
1027 cir::MemOrder order,
1028 const std::optional<Expr::EvalResult> &scopeConst,
1029 mlir::Value scopeValue) {
1030 std::unique_ptr<AtomicScopeModel> scopeModel =
expr->getScopeModel();
1034 failureOrderExpr, size, order, cir::SyncScopeKind::System);
1038 if (scopeConst.has_value()) {
1040 cgf,
expr->getScope()->getSourceRange(),
1041 scopeModel->map(scopeConst->Val.getInt().getZExtValue()));
1043 failureOrderExpr, size, order, mappedScope);
1050 mlir::Location loc = cgf.
getLoc(
expr->getSourceRange());
1052 unsigned fallback = scopeModel->getFallBackValue();
1054 cir::SwitchOp::create(
1055 builder, loc, scopeValue,
1056 [&](mlir::OpBuilder &, mlir::Location loc, mlir::OperationState &) {
1057 mlir::Block *switchBlock = builder.getBlock();
1061 cgf,
expr->getScope()->getSourceRange(), scopeModel->map(fallback));
1064 isWeakExpr, failureOrderExpr, size, order, fallbackScope);
1066 builder.setInsertionPointToEnd(switchBlock);
1069 for (
unsigned scope : allScopes) {
1070 if (scope == fallback)
1074 cgf,
expr->getScope()->getSourceRange(), scopeModel->map(scope));
1076 mlir::ArrayAttr casesAttr = builder.getArrayAttr(
1077 {cir::IntAttr::get(scopeValue.getType(), scope)});
1078 mlir::OpBuilder::InsertPoint insertPoint;
1079 cir::CaseOp::create(builder, loc, casesAttr, cir::CaseOpKind::Equal,
1082 builder.restoreInsertionPoint(insertPoint);
1084 isWeakExpr, failureOrderExpr, size, order, cirScope);
1086 builder.setInsertionPointToEnd(switchBlock);
1093static std::optional<cir::MemOrder>
1103 if (oriOrder == cir::MemOrder::Consume ||
1104 oriOrder == cir::MemOrder::Acquire ||
1105 oriOrder == cir::MemOrder::AcquireRelease)
1106 return std::nullopt;
1107 }
else if (isLoad) {
1108 if (oriOrder == cir::MemOrder::Release ||
1109 oriOrder == cir::MemOrder::AcquireRelease)
1110 return std::nullopt;
1111 }
else if (isFence) {
1112 if (oriOrder == cir::MemOrder::Relaxed)
1113 return std::nullopt;
1117 if (oriOrder == cir::MemOrder::Consume)
1118 return cir::MemOrder::Acquire;
1123 CIRGenFunction &cgf, mlir::Value order,
bool isStore,
bool isLoad,
1124 bool isFence, llvm::function_ref<
void(cir::MemOrder)> emitAtomicOpFn) {
1132 cir::SwitchOp::create(
1133 builder, order.getLoc(), order,
1134 [&](mlir::OpBuilder &, mlir::Location loc, mlir::OperationState &) {
1135 mlir::Block *switchBlock = builder.getBlock();
1137 auto emitMemOrderCase = [&](llvm::ArrayRef<cir::MemOrder> caseOrders) {
1139 for (int i = 1, e = caseOrders.size(); i < e; i++)
1140 assert((getEffectiveAtomicMemOrder(caseOrders[i - 1], isStore,
1142 getEffectiveAtomicMemOrder(caseOrders[i], isStore, isLoad,
1144 "Effective memory order must be same!");
1146 if (caseOrders.empty()) {
1147 emitDefaultCaseLabel(builder, loc);
1151 emitAtomicOpFn(cir::MemOrder::Relaxed);
1152 } else if (std::optional<cir::MemOrder> actualOrder =
1153 getEffectiveAtomicMemOrder(caseOrders[0], isStore,
1156 if (!isFence && actualOrder == cir::MemOrder::Relaxed)
1161 emitMemOrderCaseLabel(builder, loc, order.getType(), caseOrders);
1162 emitAtomicOpFn(actualOrder.value());
1167 builder.createBreak(loc);
1168 builder.setInsertionPointToEnd(switchBlock);
1171 emitMemOrderCase( {});
1172 emitMemOrderCase({cir::MemOrder::Relaxed});
1173 emitMemOrderCase({cir::MemOrder::Consume, cir::MemOrder::Acquire});
1174 emitMemOrderCase({cir::MemOrder::Release});
1175 emitMemOrderCase({cir::MemOrder::AcquireRelease});
1176 emitMemOrderCase({cir::MemOrder::SequentiallyConsistent});
1183 const Expr *memOrder,
bool isStore,
bool isLoad,
bool isFence,
1184 llvm::function_ref<
void(cir::MemOrder)> emitAtomicOpFn) {
1188 uint64_t constOrder = eval.
Val.
getInt().getZExtValue();
1193 cir::MemOrder oriOrder =
static_cast<cir::MemOrder
>(constOrder);
1194 if (std::optional<cir::MemOrder> actualOrder =
1196 emitAtomicOpFn(actualOrder.value());
1213 mlir::NamedAttrList fnAttrs;
1225 uint64_t atomicTySize,
1238 auto castToGenericAddrSpace = [&](mlir::Value v,
QualType pt) {
1243 cgf.
cgm.
errorNYI(loc,
"emitLibCallForAtomicExpr: openCL");
1253 llvm::StringRef calleeName;
1255 bool hasRetTy =
false;
1256 switch (e->
getOp()) {
1257 case AtomicExpr::AO__c11_atomic_init:
1258 case AtomicExpr::AO__opencl_atomic_init:
1259 llvm_unreachable(
"Already handled!");
1266 case AtomicExpr::AO__atomic_compare_exchange:
1267 case AtomicExpr::AO__atomic_compare_exchange_n:
1268 case AtomicExpr::AO__c11_atomic_compare_exchange_weak:
1269 case AtomicExpr::AO__c11_atomic_compare_exchange_strong:
1270 case AtomicExpr::AO__hip_atomic_compare_exchange_weak:
1271 case AtomicExpr::AO__hip_atomic_compare_exchange_strong:
1272 case AtomicExpr::AO__opencl_atomic_compare_exchange_weak:
1273 case AtomicExpr::AO__opencl_atomic_compare_exchange_strong:
1274 case AtomicExpr::AO__scoped_atomic_compare_exchange:
1275 case AtomicExpr::AO__scoped_atomic_compare_exchange_n: {
1276 calleeName =
"__atomic_compare_exchange";
1293 case AtomicExpr::AO__atomic_exchange:
1294 case AtomicExpr::AO__atomic_exchange_n:
1295 case AtomicExpr::AO__c11_atomic_exchange:
1296 case AtomicExpr::AO__hip_atomic_exchange:
1297 case AtomicExpr::AO__opencl_atomic_exchange:
1298 case AtomicExpr::AO__scoped_atomic_exchange:
1299 case AtomicExpr::AO__scoped_atomic_exchange_n:
1300 calleeName =
"__atomic_exchange";
1307 case AtomicExpr::AO__atomic_store:
1308 case AtomicExpr::AO__atomic_store_n:
1309 case AtomicExpr::AO__c11_atomic_store:
1310 case AtomicExpr::AO__hip_atomic_store:
1311 case AtomicExpr::AO__opencl_atomic_store:
1312 case AtomicExpr::AO__scoped_atomic_store:
1313 case AtomicExpr::AO__scoped_atomic_store_n:
1314 calleeName =
"__atomic_store";
1323 case AtomicExpr::AO__atomic_load:
1324 case AtomicExpr::AO__atomic_load_n:
1325 case AtomicExpr::AO__c11_atomic_load:
1326 case AtomicExpr::AO__hip_atomic_load:
1327 case AtomicExpr::AO__opencl_atomic_load:
1328 case AtomicExpr::AO__scoped_atomic_load:
1329 case AtomicExpr::AO__scoped_atomic_load_n:
1330 calleeName =
"__atomic_load";
1333 case AtomicExpr::AO__atomic_add_fetch:
1334 case AtomicExpr::AO__scoped_atomic_add_fetch:
1335 case AtomicExpr::AO__atomic_fetch_add:
1336 case AtomicExpr::AO__c11_atomic_fetch_add:
1337 case AtomicExpr::AO__hip_atomic_fetch_add:
1338 case AtomicExpr::AO__opencl_atomic_fetch_add:
1339 case AtomicExpr::AO__scoped_atomic_fetch_add:
1340 case AtomicExpr::AO__atomic_and_fetch:
1341 case AtomicExpr::AO__scoped_atomic_and_fetch:
1342 case AtomicExpr::AO__atomic_fetch_and:
1343 case AtomicExpr::AO__c11_atomic_fetch_and:
1344 case AtomicExpr::AO__hip_atomic_fetch_and:
1345 case AtomicExpr::AO__opencl_atomic_fetch_and:
1346 case AtomicExpr::AO__scoped_atomic_fetch_and:
1347 case AtomicExpr::AO__atomic_or_fetch:
1348 case AtomicExpr::AO__scoped_atomic_or_fetch:
1349 case AtomicExpr::AO__atomic_fetch_or:
1350 case AtomicExpr::AO__c11_atomic_fetch_or:
1351 case AtomicExpr::AO__hip_atomic_fetch_or:
1352 case AtomicExpr::AO__opencl_atomic_fetch_or:
1353 case AtomicExpr::AO__scoped_atomic_fetch_or:
1354 case AtomicExpr::AO__atomic_sub_fetch:
1355 case AtomicExpr::AO__scoped_atomic_sub_fetch:
1356 case AtomicExpr::AO__atomic_fetch_sub:
1357 case AtomicExpr::AO__c11_atomic_fetch_sub:
1358 case AtomicExpr::AO__hip_atomic_fetch_sub:
1359 case AtomicExpr::AO__opencl_atomic_fetch_sub:
1360 case AtomicExpr::AO__scoped_atomic_fetch_sub:
1361 case AtomicExpr::AO__atomic_xor_fetch:
1362 case AtomicExpr::AO__scoped_atomic_xor_fetch:
1363 case AtomicExpr::AO__atomic_fetch_xor:
1364 case AtomicExpr::AO__c11_atomic_fetch_xor:
1365 case AtomicExpr::AO__hip_atomic_fetch_xor:
1366 case AtomicExpr::AO__opencl_atomic_fetch_xor:
1367 case AtomicExpr::AO__scoped_atomic_fetch_xor:
1368 case AtomicExpr::AO__atomic_nand_fetch:
1369 case AtomicExpr::AO__atomic_fetch_nand:
1370 case AtomicExpr::AO__c11_atomic_fetch_nand:
1371 case AtomicExpr::AO__scoped_atomic_fetch_nand:
1372 case AtomicExpr::AO__scoped_atomic_nand_fetch:
1373 case AtomicExpr::AO__atomic_min_fetch:
1374 case AtomicExpr::AO__atomic_fetch_min:
1375 case AtomicExpr::AO__c11_atomic_fetch_min:
1376 case AtomicExpr::AO__hip_atomic_fetch_min:
1377 case AtomicExpr::AO__opencl_atomic_fetch_min:
1378 case AtomicExpr::AO__scoped_atomic_fetch_min:
1379 case AtomicExpr::AO__scoped_atomic_min_fetch:
1380 case AtomicExpr::AO__atomic_max_fetch:
1381 case AtomicExpr::AO__atomic_fetch_max:
1382 case AtomicExpr::AO__c11_atomic_fetch_max:
1383 case AtomicExpr::AO__hip_atomic_fetch_max:
1384 case AtomicExpr::AO__opencl_atomic_fetch_max:
1385 case AtomicExpr::AO__scoped_atomic_fetch_max:
1386 case AtomicExpr::AO__scoped_atomic_max_fetch:
1387 case AtomicExpr::AO__scoped_atomic_fetch_uinc:
1388 case AtomicExpr::AO__scoped_atomic_fetch_udec:
1389 case AtomicExpr::AO__atomic_fetch_fmaximum:
1390 case AtomicExpr::AO__atomic_fetch_fmaximum_num:
1391 case AtomicExpr::AO__atomic_fetch_fminimum:
1392 case AtomicExpr::AO__atomic_fetch_fminimum_num:
1393 case AtomicExpr::AO__scoped_atomic_fetch_fmaximum:
1394 case AtomicExpr::AO__scoped_atomic_fetch_fmaximum_num:
1395 case AtomicExpr::AO__scoped_atomic_fetch_fminimum:
1396 case AtomicExpr::AO__scoped_atomic_fetch_fminimum_num:
1397 case AtomicExpr::AO__atomic_test_and_set:
1398 case AtomicExpr::AO__atomic_clear:
1399 case AtomicExpr::AO__atomic_fetch_uinc:
1400 case AtomicExpr::AO__atomic_fetch_udec:
1401 llvm_unreachable(
"Integral atomic operations always become atomicrmw!");
1406 cgf.
cgm.
errorNYI(loc,
"emitLibCallForAtomicExpr: openCL");
1422 cgf.
cgm.
errorNYI(loc,
"emitLibCallForAtomicExpr: openCL");
1444 memTy = ty->getValueType();
1446 Expr *isWeakExpr =
nullptr;
1447 Expr *orderFailExpr =
nullptr;
1455 if (e->
getOp() == AtomicExpr::AO__c11_atomic_init) {
1467 std::optional<Expr::EvalResult> scopeConst;
1470 scopeConst.emplace(std::move(eval));
1472 switch (e->
getOp()) {
1477 case AtomicExpr::AO__c11_atomic_init:
1478 llvm_unreachable(
"already handled above with emitAtomicInit");
1480 case AtomicExpr::AO__atomic_load_n:
1481 case AtomicExpr::AO__scoped_atomic_load_n:
1482 case AtomicExpr::AO__c11_atomic_load:
1483 case AtomicExpr::AO__opencl_atomic_load:
1484 case AtomicExpr::AO__hip_atomic_load:
1485 case AtomicExpr::AO__atomic_test_and_set:
1486 case AtomicExpr::AO__atomic_clear:
1489 case AtomicExpr::AO__atomic_load:
1490 case AtomicExpr::AO__scoped_atomic_load:
1494 case AtomicExpr::AO__atomic_store:
1495 case AtomicExpr::AO__scoped_atomic_store:
1499 case AtomicExpr::AO__atomic_exchange:
1500 case AtomicExpr::AO__scoped_atomic_exchange:
1505 case AtomicExpr::AO__atomic_compare_exchange:
1506 case AtomicExpr::AO__atomic_compare_exchange_n:
1507 case AtomicExpr::AO__c11_atomic_compare_exchange_weak:
1508 case AtomicExpr::AO__c11_atomic_compare_exchange_strong:
1509 case AtomicExpr::AO__scoped_atomic_compare_exchange:
1510 case AtomicExpr::AO__scoped_atomic_compare_exchange_n:
1511 case AtomicExpr::AO__hip_atomic_compare_exchange_strong:
1512 case AtomicExpr::AO__hip_atomic_compare_exchange_weak:
1513 case AtomicExpr::AO__opencl_atomic_compare_exchange_strong:
1514 case AtomicExpr::AO__opencl_atomic_compare_exchange_weak:
1516 if (e->
getOp() == AtomicExpr::AO__atomic_compare_exchange ||
1517 e->
getOp() == AtomicExpr::AO__scoped_atomic_compare_exchange)
1522 if (e->
getOp() == AtomicExpr::AO__atomic_compare_exchange_n ||
1523 e->
getOp() == AtomicExpr::AO__atomic_compare_exchange ||
1524 e->
getOp() == AtomicExpr::AO__scoped_atomic_compare_exchange_n ||
1525 e->
getOp() == AtomicExpr::AO__scoped_atomic_compare_exchange)
1529 case AtomicExpr::AO__c11_atomic_fetch_add:
1530 case AtomicExpr::AO__c11_atomic_fetch_sub:
1541 mlir::Value scale = builder.getConstInt(loc, val1Scalar.getType(),
1543 val1Scalar = builder.createMul(loc, val1Scalar, scale);
1549 case AtomicExpr::AO__atomic_fetch_add:
1550 case AtomicExpr::AO__atomic_fetch_sub:
1551 case AtomicExpr::AO__atomic_add_fetch:
1552 case AtomicExpr::AO__atomic_sub_fetch:
1562 case AtomicExpr::AO__atomic_fetch_max:
1563 case AtomicExpr::AO__atomic_fetch_min:
1564 case AtomicExpr::AO__atomic_max_fetch:
1565 case AtomicExpr::AO__atomic_min_fetch:
1566 case AtomicExpr::AO__c11_atomic_fetch_max:
1567 case AtomicExpr::AO__c11_atomic_fetch_min:
1568 case AtomicExpr::AO__scoped_atomic_fetch_add:
1569 case AtomicExpr::AO__scoped_atomic_fetch_max:
1570 case AtomicExpr::AO__scoped_atomic_fetch_min:
1571 case AtomicExpr::AO__scoped_atomic_fetch_sub:
1572 case AtomicExpr::AO__scoped_atomic_fetch_fminimum:
1573 case AtomicExpr::AO__scoped_atomic_fetch_fmaximum:
1574 case AtomicExpr::AO__scoped_atomic_fetch_fminimum_num:
1575 case AtomicExpr::AO__scoped_atomic_fetch_fmaximum_num:
1576 case AtomicExpr::AO__scoped_atomic_add_fetch:
1577 case AtomicExpr::AO__scoped_atomic_max_fetch:
1578 case AtomicExpr::AO__scoped_atomic_min_fetch:
1579 case AtomicExpr::AO__scoped_atomic_sub_fetch:
1582 case AtomicExpr::AO__atomic_fetch_and:
1583 case AtomicExpr::AO__atomic_fetch_nand:
1584 case AtomicExpr::AO__atomic_fetch_or:
1585 case AtomicExpr::AO__atomic_fetch_xor:
1586 case AtomicExpr::AO__atomic_and_fetch:
1587 case AtomicExpr::AO__atomic_nand_fetch:
1588 case AtomicExpr::AO__atomic_or_fetch:
1589 case AtomicExpr::AO__atomic_xor_fetch:
1590 case AtomicExpr::AO__atomic_exchange_n:
1591 case AtomicExpr::AO__atomic_store_n:
1592 case AtomicExpr::AO__c11_atomic_fetch_and:
1593 case AtomicExpr::AO__c11_atomic_fetch_nand:
1594 case AtomicExpr::AO__c11_atomic_fetch_or:
1595 case AtomicExpr::AO__c11_atomic_fetch_xor:
1596 case AtomicExpr::AO__c11_atomic_exchange:
1597 case AtomicExpr::AO__c11_atomic_store:
1598 case AtomicExpr::AO__scoped_atomic_fetch_and:
1599 case AtomicExpr::AO__scoped_atomic_fetch_nand:
1600 case AtomicExpr::AO__scoped_atomic_fetch_or:
1601 case AtomicExpr::AO__scoped_atomic_fetch_xor:
1602 case AtomicExpr::AO__scoped_atomic_and_fetch:
1603 case AtomicExpr::AO__scoped_atomic_nand_fetch:
1604 case AtomicExpr::AO__scoped_atomic_or_fetch:
1605 case AtomicExpr::AO__scoped_atomic_xor_fetch:
1606 case AtomicExpr::AO__scoped_atomic_store_n:
1607 case AtomicExpr::AO__scoped_atomic_exchange_n:
1608 case AtomicExpr::AO__atomic_fetch_uinc:
1609 case AtomicExpr::AO__atomic_fetch_udec:
1610 case AtomicExpr::AO__scoped_atomic_fetch_uinc:
1611 case AtomicExpr::AO__scoped_atomic_fetch_udec:
1612 case AtomicExpr::AO__atomic_fetch_fminimum:
1613 case AtomicExpr::AO__atomic_fetch_fmaximum:
1614 case AtomicExpr::AO__atomic_fetch_fminimum_num:
1615 case AtomicExpr::AO__atomic_fetch_fmaximum_num:
1616 case AtomicExpr::AO__hip_atomic_exchange:
1617 case AtomicExpr::AO__hip_atomic_store:
1618 case AtomicExpr::AO__hip_atomic_fetch_add:
1619 case AtomicExpr::AO__hip_atomic_fetch_sub:
1620 case AtomicExpr::AO__hip_atomic_fetch_min:
1621 case AtomicExpr::AO__hip_atomic_fetch_max:
1622 case AtomicExpr::AO__hip_atomic_fetch_and:
1623 case AtomicExpr::AO__hip_atomic_fetch_or:
1624 case AtomicExpr::AO__hip_atomic_fetch_xor:
1625 case AtomicExpr::AO__opencl_atomic_exchange:
1626 case AtomicExpr::AO__opencl_atomic_store:
1627 case AtomicExpr::AO__opencl_atomic_fetch_add:
1628 case AtomicExpr::AO__opencl_atomic_fetch_sub:
1629 case AtomicExpr::AO__opencl_atomic_fetch_min:
1630 case AtomicExpr::AO__opencl_atomic_fetch_max:
1631 case AtomicExpr::AO__opencl_atomic_fetch_and:
1632 case AtomicExpr::AO__opencl_atomic_fetch_or:
1633 case AtomicExpr::AO__opencl_atomic_fetch_xor:
1640 bool shouldCastToIntPtrTy =
1648 AtomicInfo atomics(*
this, atomicValue, loc);
1654 if (shouldCastToIntPtrTy) {
1655 ptr = atomics.castToAtomicIntPointer(ptr);
1657 val1 = atomics.convertToAtomicIntPointer(val1, loc);
1659 val2 = atomics.convertToAtomicIntPointer(val2, loc);
1662 if (shouldCastToIntPtrTy)
1663 dest = atomics.castToAtomicIntPointer(dest);
1666 }
else if (e->
getOp() == AtomicExpr::AO__atomic_test_and_set) {
1669 dest = atomics.createTempAlloca();
1670 if (shouldCastToIntPtrTy)
1671 dest = atomics.castToAtomicIntPointer(dest);
1674 bool powerOf2Size = (size & (size - 1)) == 0;
1675 bool useLibCall = !powerOf2Size || (size > 16);
1690 bool isStore = e->
getOp() == AtomicExpr::AO__c11_atomic_store ||
1691 e->
getOp() == AtomicExpr::AO__opencl_atomic_store ||
1692 e->
getOp() == AtomicExpr::AO__hip_atomic_store ||
1693 e->
getOp() == AtomicExpr::AO__atomic_store ||
1694 e->
getOp() == AtomicExpr::AO__atomic_store_n ||
1695 e->
getOp() == AtomicExpr::AO__scoped_atomic_store ||
1696 e->
getOp() == AtomicExpr::AO__scoped_atomic_store_n ||
1697 e->
getOp() == AtomicExpr::AO__atomic_clear;
1698 bool isLoad = e->
getOp() == AtomicExpr::AO__c11_atomic_load ||
1699 e->
getOp() == AtomicExpr::AO__opencl_atomic_load ||
1700 e->
getOp() == AtomicExpr::AO__hip_atomic_load ||
1701 e->
getOp() == AtomicExpr::AO__atomic_load ||
1702 e->
getOp() == AtomicExpr::AO__atomic_load_n ||
1703 e->
getOp() == AtomicExpr::AO__scoped_atomic_load ||
1704 e->
getOp() == AtomicExpr::AO__scoped_atomic_load_n;
1706 auto emitAtomicOpCallBackFn = [&](cir::MemOrder memOrder) {
1707 emitAtomicOp(*
this, e, dest, ptr, val1, val2, originalVal1, isWeakExpr,
1708 orderFailExpr, size, memOrder, scopeConst, scope);
1711 emitAtomicOpCallBackFn);
1724 return emitAtomicLoad(lvalue, loc, cir::MemOrder::SequentiallyConsistent,
1731 cir::MemOrder order,
bool isVolatile,
1733 AtomicInfo info(*
this, lvalue,
getLoc(loc));
1734 return info.emitAtomicLoad(slot, loc,
true, order, isVolatile);
1739 auto order = cir::MemOrder::SequentiallyConsistent;
1752 cir::MemOrder order,
bool isVolatile,
1756 mlir::Location loc = dest.
getPointer().getLoc();
1761 AtomicInfo atomics(*
this, dest, loc);
1762 LValue lvalue = atomics.getAtomicLValue();
1767 atomics.emitCopyIntoMemory(rvalue);
1772 if (atomics.shouldUseLibCall()) {
1774 cgm.errorNYI(loc,
"emitAtomicStore: atomic store with library call");
1779 mlir::Value valueToStore = atomics.convertRValueToInt(rvalue, loc);
1782 Address addr = atomics.getAtomicAddress();
1783 if (mlir::Value value = atomics.getScalarRValValueOrNull(rvalue)) {
1785 addr = atomics.castToAtomicIntPointer(addr);
1790 cir::StoreOp store = builder.createStore(loc, valueToStore, addr);
1795 store.setMemOrder(order);
1800 store.setIsVolatile(
true);
1806 cgm.errorNYI(loc,
"emitAtomicStore: non-simple atomic lvalue");
1813 switch (atomics.getEvaluationKind()) {
1829 bool zeroed =
false;
1831 zeroed = atomics.emitMemSetZeroIfNecessary();
1832 dest = atomics.projectValue();
1847 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)
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
cir::FuncOp createRuntimeFunction(cir::FuncType ty, llvm::StringRef name, mlir::NamedAttrList extraAttrs={}, bool isLocal=false, bool assumeConvergent=false)
const cir::CIRDataLayout getDataLayout() const
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 atomicAMDGPUNoaliasAddrspace()
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.