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)
const;
115 RValue convertAtomicTempToRValue(Address addr, SourceLocation loc,
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",
138 return LValue::makeAddr(addr, getValueType(), lvalue.getBaseInfo());
143 RValue emitAtomicLoad(AggValueSlot resultSlot, SourceLocation loc,
144 bool asValue, cir::MemOrder order,
bool isVolatile);
147 Address materializeRValue(RValue rvalue, mlir::Location loc)
const;
150 Address createTempAlloca()
const;
153 bool requiresMemSetZero(mlir::Type ty)
const;
156 mlir::Value emitAtomicLoadOp(cir::MemOrder order,
bool isVolatile,
157 bool cmpxchg =
false);
173 uint64_t expectedSize) {
180bool AtomicInfo::requiresMemSetZero(mlir::Type ty)
const {
186 switch (getEvaluationKind()) {
193 mlir::cast<cir::ComplexType>(ty).getElementType(),
194 atomicSizeInBits / 2);
199 llvm_unreachable(
"bad evaluation kind");
202Address AtomicInfo::convertToAtomicIntPointer(Address addr)
const {
205 if (sourceSizeInBits != atomicSizeInBits) {
208 "AtomicInfo::convertToAtomicIntPointer: convert through temp alloca");
211 return castToAtomicIntPointer(addr);
214RValue AtomicInfo::convertAtomicTempToRValue(Address addr, SourceLocation loc,
215 bool asValue)
const {
216 if (lvalue.isSimple()) {
220 "AtomicInfo::convertAtomicTempToRValue: evaluationKind is aggregate");
227 "AtomicInfo::convertAtomicTempToRValue: hasPadding");
237 loc,
"AtomicInfo::convertAtomicTempToRValue: lvalue is not simple");
241RValue AtomicInfo::emitAtomicLoad(AggValueSlot resultSlot, SourceLocation loc,
242 bool asValue, cir::MemOrder order,
245 if (shouldUseLibCall()) {
247 cgf.
cgm.
errorNYI(loc,
"emitAtomicLoad: emit atomic lib call");
252 mlir::Value loadOp = emitAtomicLoadOp(order, isVolatile);
260 return convertToValueOrAtomic(loadOp, resultSlot, loc, asValue);
263Address AtomicInfo::createTempAlloca()
const {
266 QualType tmpTy = (lvalue.isBitField() && valueSizeInBits > atomicSizeInBits)
270 cgf.
createMemTemp(tmpTy, getAtomicAlignment(), loc,
"atomic-temp");
273 if (lvalue.isBitField()) {
274 cgf.
cgm.
errorNYI(loc,
"AtomicInfo::createTempAlloca: bitfield lvalue");
280mlir::Value AtomicInfo::getScalarRValValueOrNull(RValue rvalue)
const {
281 if (rvalue.
isScalar() && (!hasPadding() || !lvalue.isSimple()))
286Address AtomicInfo::castToAtomicIntPointer(Address addr)
const {
289 if (intTy && intTy.getWidth() == atomicSizeInBits)
295bool AtomicInfo::emitMemSetZeroIfNecessary()
const {
296 assert(lvalue.isSimple());
297 Address addr = lvalue.getAddress();
317 if (cir::isAnyFloatingPointType(valueTy))
322mlir::Value AtomicInfo::emitAtomicLoadOp(cir::MemOrder order,
bool isVolatile,
324 Address addr = getAtomicAddress();
326 addr = castToAtomicIntPointer(addr);
330 op.setMemOrder(order);
336mlir::Value AtomicInfo::convertRValueToInt(RValue rvalue, mlir::Location loc,
337 bool cmpxchg)
const {
340 if (mlir::Value value = getScalarRValValueOrNull(rvalue)) {
345 loc,
"AtomicInfo::convertRValueToInt: cast scalar rvalue to int");
351 Address addr = materializeRValue(rvalue, loc);
354 addr = castToAtomicIntPointer(addr);
359RValue AtomicInfo::convertToValueOrAtomic(mlir::Value intVal,
360 AggValueSlot resultSlot,
361 SourceLocation loc,
bool asValue,
362 bool cmpxchg)
const {
364 assert((mlir::isa<cir::IntType, cir::PointerType, cir::FPTypeInterface>(
365 intVal.getType())) &&
366 "Expected integer, pointer or floating point value when converting "
369 !lvalue.isBitField() || lvalue.getBitFieldInfo().size == valueSizeInBits;
371 ((isWholeValue && !hasPadding()) || !asValue)) {
373 : getAtomicAddress().getElementType();
375 assert((!mlir::isa<cir::IntType>(valTy) || intVal.getType() == valTy) &&
376 "Different integer types.");
380 cgf.
cgm.
errorNYI(
"convertToValueOrAtomic: convert through bitcast");
388 cgf.
cgm.
errorNYI(
"convertToValueOrAtomic: temporary aggregate");
391 temp = createTempAlloca();
395 Address castTemp = castToAtomicIntPointer(temp);
397 return convertAtomicTempToRValue(temp, loc, asValue);
402void AtomicInfo::emitCopyIntoMemory(RValue rvalue)
const {
403 assert(lvalue.isSimple());
409 cgf.
cgm.
errorNYI(
"copying aggregate into atomic lvalue");
416 emitMemSetZeroIfNecessary();
419 LValue tempLValue = projectValue();
432Address AtomicInfo::materializeRValue(RValue rvalue, mlir::Location loc)
const {
439 LValue tempLV = cgf.
makeAddrLValue(createTempAlloca(), getAtomicType());
440 AtomicInfo atomics(cgf, tempLV, loc);
442 atomics.emitCopyIntoMemory(rvalue);
443 return tempLV.getAddress();
447 mlir::ArrayAttr valuesAttr = builder.getArrayAttr({});
448 mlir::OpBuilder::InsertPoint insertPoint;
449 cir::CaseOp::create(builder, loc, valuesAttr, cir::CaseOpKind::Default,
451 builder.restoreInsertionPoint(insertPoint);
457 mlir::Type orderType,
460 for (cir::MemOrder order : orders)
461 orderAttrs.push_back(cir::IntAttr::get(orderType,
static_cast<int>(order)));
462 mlir::ArrayAttr ordersAttr = builder.getArrayAttr(orderAttrs);
464 mlir::OpBuilder::InsertPoint insertPoint;
465 cir::CaseOp::create(builder, loc, ordersAttr, cir::CaseOpKind::Anyof,
467 builder.restoreInsertionPoint(insertPoint);
473 cir::MemOrder successOrder,
474 cir::MemOrder failureOrder,
475 cir::SyncScopeKind scope) {
479 mlir::Value expected = builder.
createLoad(loc, val1);
480 mlir::Value desired = builder.
createLoad(loc, val2);
482 auto cmpxchg = cir::AtomicCmpXchgOp::create(
491 cmpxchg.setWeak(isWeak);
493 mlir::Value failed = builder.
createNot(cmpxchg.getSuccess());
494 cir::IfOp::create(builder, loc, failed,
false,
495 [&](mlir::OpBuilder &, mlir::Location) {
496 auto ptrTy = mlir::cast<cir::PointerType>(
515 Expr *failureOrderExpr, uint64_t size,
516 cir::MemOrder successOrder,
517 cir::SyncScopeKind scope) {
520 uint64_t failureOrderInt = failureOrderEval.
Val.
getInt().getZExtValue();
522 cir::MemOrder failureOrder;
524 failureOrder = cir::MemOrder::Relaxed;
526 switch ((cir::MemOrder)failureOrderInt) {
527 case cir::MemOrder::Relaxed:
530 case cir::MemOrder::Release:
531 case cir::MemOrder::AcquireRelease:
532 failureOrder = cir::MemOrder::Relaxed;
534 case cir::MemOrder::Consume:
535 case cir::MemOrder::Acquire:
536 failureOrder = cir::MemOrder::Acquire;
538 case cir::MemOrder::SequentiallyConsistent:
539 failureOrder = cir::MemOrder::SequentiallyConsistent;
549 failureOrder, scope);
557 mlir::Value failureOrderVal = cgf.
emitScalarExpr(failureOrderExpr);
559 cir::SwitchOp::create(
561 [&](mlir::OpBuilder &b, mlir::Location loc, mlir::OperationState &os) {
562 mlir::Block *switchBlock = cgf.getBuilder().getBlock();
574 emitDefaultCaseLabel(cgf.getBuilder(), atomicLoc);
575 emitAtomicCmpXchg(cgf, e, isWeak, dest, ptr, val1, val2, size,
576 successOrder, cir::MemOrder::Relaxed, scope);
577 cgf.getBuilder().createBreak(atomicLoc);
578 cgf.getBuilder().setInsertionPointToEnd(switchBlock);
582 emitMemOrderCaseLabel(cgf.getBuilder(), loc, failureOrderVal.getType(),
583 {cir::MemOrder::Consume, cir::MemOrder::Acquire});
585 successOrder, cir::MemOrder::Acquire, scope);
587 cgf.
getBuilder().setInsertionPointToEnd(switchBlock);
591 {cir::MemOrder::SequentiallyConsistent});
593 successOrder, cir::MemOrder::SequentiallyConsistent,
596 cgf.
getBuilder().setInsertionPointToEnd(switchBlock);
608 uint64_t size, cir::MemOrder successOrder, cir::SyncScopeKind scope) {
620 [&](mlir::OpBuilder &b, mlir::Location loc) {
621 emitAtomicCmpXchgFailureSet(cgf, e, true, dest, ptr, val1,
622 val2, failureOrderExpr, size, successOrder,
624 cgf.getBuilder().createYield(atomicLoc);
626 [&](mlir::OpBuilder &b, mlir::Location loc) {
627 emitAtomicCmpXchgFailureSet(cgf, e, false, dest, ptr, val1,
628 val2, failureOrderExpr, size, successOrder,
630 cgf.getBuilder().createYield(atomicLoc);
636 Expr *isWeakExpr,
Expr *failureOrderExpr, int64_t size,
637 cir::MemOrder order, cir::SyncScopeKind scope) {
639 llvm::StringRef opName;
642 mlir::Location loc = cgf.
getLoc(
expr->getSourceRange());
643 auto orderAttr = cir::MemOrderAttr::get(builder.getContext(), order);
644 auto scopeAttr = cir::SyncScopeKindAttr::get(builder.getContext(), scope);
645 cir::AtomicFetchKindAttr fetchAttr;
646 bool fetchFirst =
true;
648 auto handleFetchOp = [&](cir::AtomicFetchKind
kind) {
649 opName = cir::AtomicFetchOp::getOperationName();
650 fetchAttr = cir::AtomicFetchKindAttr::get(builder.getContext(),
kind);
653 switch (
expr->getOp()) {
654 case AtomicExpr::AO__c11_atomic_init:
655 llvm_unreachable(
"already handled!");
657 case AtomicExpr::AO__c11_atomic_compare_exchange_strong:
659 val2, failureOrderExpr, size, order, scope);
662 case AtomicExpr::AO__c11_atomic_compare_exchange_weak:
664 val2, failureOrderExpr, size, order, scope);
667 case AtomicExpr::AO__atomic_compare_exchange:
668 case AtomicExpr::AO__atomic_compare_exchange_n:
669 case AtomicExpr::AO__scoped_atomic_compare_exchange:
670 case AtomicExpr::AO__scoped_atomic_compare_exchange_n: {
674 failureOrderExpr, size, order, scope);
677 val1, val2, failureOrderExpr, size,
683 case AtomicExpr::AO__c11_atomic_load:
684 case AtomicExpr::AO__atomic_load_n:
685 case AtomicExpr::AO__atomic_load:
686 case AtomicExpr::AO__scoped_atomic_load_n:
687 case AtomicExpr::AO__scoped_atomic_load: {
691 load->setAttr(
"mem_order", orderAttr);
692 load->setAttr(
"sync_scope", scopeAttr);
694 builder.
createStore(loc, load->getResult(0), dest);
698 case AtomicExpr::AO__c11_atomic_store:
699 case AtomicExpr::AO__atomic_store_n:
700 case AtomicExpr::AO__atomic_store:
701 case AtomicExpr::AO__scoped_atomic_store:
702 case AtomicExpr::AO__scoped_atomic_store_n: {
703 cir::LoadOp loadVal1 = builder.
createLoad(loc, val1);
708 mlir::IntegerAttr{}, scopeAttr, orderAttr);
712 case AtomicExpr::AO__c11_atomic_exchange:
713 case AtomicExpr::AO__atomic_exchange_n:
714 case AtomicExpr::AO__atomic_exchange:
715 case AtomicExpr::AO__scoped_atomic_exchange_n:
716 case AtomicExpr::AO__scoped_atomic_exchange:
717 opName = cir::AtomicXchgOp::getOperationName();
720 case AtomicExpr::AO__atomic_add_fetch:
721 case AtomicExpr::AO__scoped_atomic_add_fetch:
724 case AtomicExpr::AO__c11_atomic_fetch_add:
725 case AtomicExpr::AO__atomic_fetch_add:
726 case AtomicExpr::AO__scoped_atomic_fetch_add:
727 handleFetchOp(cir::AtomicFetchKind::Add);
730 case AtomicExpr::AO__atomic_sub_fetch:
731 case AtomicExpr::AO__scoped_atomic_sub_fetch:
734 case AtomicExpr::AO__c11_atomic_fetch_sub:
735 case AtomicExpr::AO__atomic_fetch_sub:
736 case AtomicExpr::AO__scoped_atomic_fetch_sub:
737 handleFetchOp(cir::AtomicFetchKind::Sub);
740 case AtomicExpr::AO__atomic_min_fetch:
741 case AtomicExpr::AO__scoped_atomic_min_fetch:
744 case AtomicExpr::AO__c11_atomic_fetch_min:
745 case AtomicExpr::AO__atomic_fetch_min:
746 case AtomicExpr::AO__scoped_atomic_fetch_min:
747 handleFetchOp(cir::AtomicFetchKind::Min);
750 case AtomicExpr::AO__atomic_max_fetch:
751 case AtomicExpr::AO__scoped_atomic_max_fetch:
754 case AtomicExpr::AO__c11_atomic_fetch_max:
755 case AtomicExpr::AO__atomic_fetch_max:
756 case AtomicExpr::AO__scoped_atomic_fetch_max:
757 handleFetchOp(cir::AtomicFetchKind::Max);
760 case AtomicExpr::AO__atomic_and_fetch:
761 case AtomicExpr::AO__scoped_atomic_and_fetch:
764 case AtomicExpr::AO__c11_atomic_fetch_and:
765 case AtomicExpr::AO__atomic_fetch_and:
766 case AtomicExpr::AO__scoped_atomic_fetch_and:
767 handleFetchOp(cir::AtomicFetchKind::And);
770 case AtomicExpr::AO__atomic_or_fetch:
771 case AtomicExpr::AO__scoped_atomic_or_fetch:
774 case AtomicExpr::AO__c11_atomic_fetch_or:
775 case AtomicExpr::AO__atomic_fetch_or:
776 case AtomicExpr::AO__scoped_atomic_fetch_or:
777 handleFetchOp(cir::AtomicFetchKind::Or);
780 case AtomicExpr::AO__atomic_xor_fetch:
781 case AtomicExpr::AO__scoped_atomic_xor_fetch:
784 case AtomicExpr::AO__c11_atomic_fetch_xor:
785 case AtomicExpr::AO__atomic_fetch_xor:
786 case AtomicExpr::AO__scoped_atomic_fetch_xor:
787 handleFetchOp(cir::AtomicFetchKind::Xor);
790 case AtomicExpr::AO__atomic_nand_fetch:
791 case AtomicExpr::AO__scoped_atomic_nand_fetch:
794 case AtomicExpr::AO__c11_atomic_fetch_nand:
795 case AtomicExpr::AO__atomic_fetch_nand:
796 case AtomicExpr::AO__scoped_atomic_fetch_nand:
797 handleFetchOp(cir::AtomicFetchKind::Nand);
800 case AtomicExpr::AO__atomic_test_and_set: {
801 auto op = cir::AtomicTestAndSetOp::create(
809 case AtomicExpr::AO__atomic_clear: {
810 cir::AtomicClearOp::create(
817 case AtomicExpr::AO__atomic_fetch_uinc:
818 case AtomicExpr::AO__scoped_atomic_fetch_uinc:
819 handleFetchOp(cir::AtomicFetchKind::UIncWrap);
822 case AtomicExpr::AO__atomic_fetch_udec:
823 case AtomicExpr::AO__scoped_atomic_fetch_udec:
824 handleFetchOp(cir::AtomicFetchKind::UDecWrap);
827 case AtomicExpr::AO__opencl_atomic_init:
829 case AtomicExpr::AO__hip_atomic_compare_exchange_strong:
830 case AtomicExpr::AO__opencl_atomic_compare_exchange_strong:
832 case AtomicExpr::AO__opencl_atomic_compare_exchange_weak:
833 case AtomicExpr::AO__hip_atomic_compare_exchange_weak:
835 case AtomicExpr::AO__opencl_atomic_load:
836 case AtomicExpr::AO__hip_atomic_load:
838 case AtomicExpr::AO__opencl_atomic_store:
839 case AtomicExpr::AO__hip_atomic_store:
841 case AtomicExpr::AO__hip_atomic_exchange:
842 case AtomicExpr::AO__opencl_atomic_exchange:
844 case AtomicExpr::AO__hip_atomic_fetch_add:
845 case AtomicExpr::AO__opencl_atomic_fetch_add:
847 case AtomicExpr::AO__hip_atomic_fetch_sub:
848 case AtomicExpr::AO__opencl_atomic_fetch_sub:
850 case AtomicExpr::AO__hip_atomic_fetch_min:
851 case AtomicExpr::AO__opencl_atomic_fetch_min:
853 case AtomicExpr::AO__hip_atomic_fetch_max:
854 case AtomicExpr::AO__opencl_atomic_fetch_max:
856 case AtomicExpr::AO__hip_atomic_fetch_and:
857 case AtomicExpr::AO__opencl_atomic_fetch_and:
859 case AtomicExpr::AO__hip_atomic_fetch_or:
860 case AtomicExpr::AO__opencl_atomic_fetch_or:
862 case AtomicExpr::AO__hip_atomic_fetch_xor:
863 case AtomicExpr::AO__opencl_atomic_fetch_xor:
868 assert(!opName.empty() &&
"expected operation name to build");
869 mlir::Value loadVal1 = builder.
createLoad(loc, val1);
873 mlir::Operation *rmwOp = builder.create(loc, builder.getStringAttr(opName),
874 atomicOperands, atomicResTys);
877 rmwOp->setAttr(
"binop", fetchAttr);
878 rmwOp->setAttr(
"mem_order", orderAttr);
879 rmwOp->setAttr(
"sync_scope", scopeAttr);
880 if (
expr->isVolatile())
881 rmwOp->setAttr(
"is_volatile", builder.getUnitAttr());
882 if (fetchFirst && opName == cir::AtomicFetchOp::getOperationName())
883 rmwOp->setAttr(
"fetch_first", builder.getUnitAttr());
885 mlir::Value result = rmwOp->getResult(0);
896 return cir::SyncScopeKind::SingleThread;
898 return cir::SyncScopeKind::System;
900 return cir::SyncScopeKind::Device;
902 return cir::SyncScopeKind::Workgroup;
904 return cir::SyncScopeKind::Wavefront;
906 return cir::SyncScopeKind::Cluster;
909 return cir::SyncScopeKind::HIPSingleThread;
911 return cir::SyncScopeKind::HIPSystem;
913 return cir::SyncScopeKind::HIPAgent;
915 return cir::SyncScopeKind::HIPWorkgroup;
917 return cir::SyncScopeKind::HIPWavefront;
919 return cir::SyncScopeKind::HIPCluster;
922 return cir::SyncScopeKind::OpenCLWorkGroup;
924 return cir::SyncScopeKind::OpenCLDevice;
926 return cir::SyncScopeKind::OpenCLAllSVMDevices;
928 return cir::SyncScopeKind::OpenCLSubGroup;
931 llvm_unreachable(
"unhandled sync scope");
936 Expr *isWeakExpr,
Expr *failureOrderExpr, int64_t size,
938 const std::optional<Expr::EvalResult> &scopeConst,
939 mlir::Value scopeValue) {
940 std::unique_ptr<AtomicScopeModel> scopeModel =
expr->getScopeModel();
943 emitAtomicOp(cgf,
expr, dest, ptr, val1, val2, isWeakExpr, failureOrderExpr,
944 size, order, cir::SyncScopeKind::System);
948 if (scopeConst.has_value()) {
950 cgf,
expr->getScope()->getSourceRange(),
951 scopeModel->map(scopeConst->Val.getInt().getZExtValue()));
952 emitAtomicOp(cgf,
expr, dest, ptr, val1, val2, isWeakExpr, failureOrderExpr,
953 size, order, mappedScope);
960 mlir::Location loc = cgf.
getLoc(
expr->getSourceRange());
962 unsigned fallback = scopeModel->getFallBackValue();
964 cir::SwitchOp::create(
965 builder, loc, scopeValue,
966 [&](mlir::OpBuilder &, mlir::Location loc, mlir::OperationState &) {
967 mlir::Block *switchBlock = builder.getBlock();
971 cgf,
expr->getScope()->getSourceRange(), scopeModel->map(fallback));
974 failureOrderExpr, size, order, fallbackScope);
976 builder.setInsertionPointToEnd(switchBlock);
979 for (
unsigned scope : allScopes) {
980 if (scope == fallback)
984 cgf,
expr->getScope()->getSourceRange(), scopeModel->map(scope));
986 mlir::ArrayAttr casesAttr = builder.getArrayAttr(
987 {cir::IntAttr::get(scopeValue.getType(), scope)});
988 mlir::OpBuilder::InsertPoint insertPoint;
989 cir::CaseOp::create(builder, loc, casesAttr, cir::CaseOpKind::Equal,
992 builder.restoreInsertionPoint(insertPoint);
994 failureOrderExpr, size, order, cirScope);
996 builder.setInsertionPointToEnd(switchBlock);
1003static std::optional<cir::MemOrder>
1013 if (oriOrder == cir::MemOrder::Consume ||
1014 oriOrder == cir::MemOrder::Acquire ||
1015 oriOrder == cir::MemOrder::AcquireRelease)
1016 return std::nullopt;
1017 }
else if (isLoad) {
1018 if (oriOrder == cir::MemOrder::Release ||
1019 oriOrder == cir::MemOrder::AcquireRelease)
1020 return std::nullopt;
1021 }
else if (isFence) {
1022 if (oriOrder == cir::MemOrder::Relaxed)
1023 return std::nullopt;
1027 if (oriOrder == cir::MemOrder::Consume)
1028 return cir::MemOrder::Acquire;
1033 CIRGenFunction &cgf, mlir::Value order,
bool isStore,
bool isLoad,
1034 bool isFence, llvm::function_ref<
void(cir::MemOrder)> emitAtomicOpFn) {
1042 cir::SwitchOp::create(
1043 builder, order.getLoc(), order,
1044 [&](mlir::OpBuilder &, mlir::Location loc, mlir::OperationState &) {
1045 mlir::Block *switchBlock = builder.getBlock();
1047 auto emitMemOrderCase = [&](llvm::ArrayRef<cir::MemOrder> caseOrders) {
1049 for (int i = 1, e = caseOrders.size(); i < e; i++)
1050 assert((getEffectiveAtomicMemOrder(caseOrders[i - 1], isStore,
1052 getEffectiveAtomicMemOrder(caseOrders[i], isStore, isLoad,
1054 "Effective memory order must be same!");
1056 if (caseOrders.empty()) {
1057 emitDefaultCaseLabel(builder, loc);
1061 emitAtomicOpFn(cir::MemOrder::Relaxed);
1062 } else if (std::optional<cir::MemOrder> actualOrder =
1063 getEffectiveAtomicMemOrder(caseOrders[0], isStore,
1066 if (!isFence && actualOrder == cir::MemOrder::Relaxed)
1071 emitMemOrderCaseLabel(builder, loc, order.getType(), caseOrders);
1072 emitAtomicOpFn(actualOrder.value());
1077 builder.createBreak(loc);
1078 builder.setInsertionPointToEnd(switchBlock);
1081 emitMemOrderCase( {});
1082 emitMemOrderCase({cir::MemOrder::Relaxed});
1083 emitMemOrderCase({cir::MemOrder::Consume, cir::MemOrder::Acquire});
1084 emitMemOrderCase({cir::MemOrder::Release});
1085 emitMemOrderCase({cir::MemOrder::AcquireRelease});
1086 emitMemOrderCase({cir::MemOrder::SequentiallyConsistent});
1093 const Expr *memOrder,
bool isStore,
bool isLoad,
bool isFence,
1094 llvm::function_ref<
void(cir::MemOrder)> emitAtomicOpFn) {
1098 uint64_t constOrder = eval.
Val.
getInt().getZExtValue();
1103 cir::MemOrder oriOrder =
static_cast<cir::MemOrder
>(constOrder);
1104 if (std::optional<cir::MemOrder> actualOrder =
1106 emitAtomicOpFn(actualOrder.value());
1121 memTy = ty->getValueType();
1123 Expr *isWeakExpr =
nullptr;
1124 Expr *orderFailExpr =
nullptr;
1132 if (e->
getOp() == AtomicExpr::AO__c11_atomic_init) {
1144 std::optional<Expr::EvalResult> scopeConst;
1147 scopeConst.emplace(std::move(eval));
1149 switch (e->
getOp()) {
1154 case AtomicExpr::AO__c11_atomic_init:
1155 llvm_unreachable(
"already handled above with emitAtomicInit");
1157 case AtomicExpr::AO__atomic_load_n:
1158 case AtomicExpr::AO__scoped_atomic_load_n:
1159 case AtomicExpr::AO__c11_atomic_load:
1160 case AtomicExpr::AO__atomic_test_and_set:
1161 case AtomicExpr::AO__atomic_clear:
1164 case AtomicExpr::AO__atomic_load:
1165 case AtomicExpr::AO__scoped_atomic_load:
1169 case AtomicExpr::AO__atomic_store:
1170 case AtomicExpr::AO__scoped_atomic_store:
1174 case AtomicExpr::AO__atomic_exchange:
1175 case AtomicExpr::AO__scoped_atomic_exchange:
1180 case AtomicExpr::AO__atomic_compare_exchange:
1181 case AtomicExpr::AO__atomic_compare_exchange_n:
1182 case AtomicExpr::AO__c11_atomic_compare_exchange_weak:
1183 case AtomicExpr::AO__c11_atomic_compare_exchange_strong:
1184 case AtomicExpr::AO__scoped_atomic_compare_exchange:
1185 case AtomicExpr::AO__scoped_atomic_compare_exchange_n:
1187 if (e->
getOp() == AtomicExpr::AO__atomic_compare_exchange ||
1188 e->
getOp() == AtomicExpr::AO__scoped_atomic_compare_exchange)
1193 if (e->
getOp() == AtomicExpr::AO__atomic_compare_exchange_n ||
1194 e->
getOp() == AtomicExpr::AO__atomic_compare_exchange ||
1195 e->
getOp() == AtomicExpr::AO__scoped_atomic_compare_exchange_n ||
1196 e->
getOp() == AtomicExpr::AO__scoped_atomic_compare_exchange)
1200 case AtomicExpr::AO__c11_atomic_fetch_add:
1201 case AtomicExpr::AO__c11_atomic_fetch_sub:
1212 mlir::Value scale = builder.getConstInt(loc, val1Scalar.getType(),
1214 val1Scalar = builder.createMul(loc, val1Scalar, scale);
1220 case AtomicExpr::AO__atomic_fetch_add:
1221 case AtomicExpr::AO__atomic_fetch_sub:
1222 case AtomicExpr::AO__atomic_add_fetch:
1223 case AtomicExpr::AO__atomic_sub_fetch:
1233 case AtomicExpr::AO__atomic_fetch_max:
1234 case AtomicExpr::AO__atomic_fetch_min:
1235 case AtomicExpr::AO__atomic_max_fetch:
1236 case AtomicExpr::AO__atomic_min_fetch:
1237 case AtomicExpr::AO__c11_atomic_fetch_max:
1238 case AtomicExpr::AO__c11_atomic_fetch_min:
1239 case AtomicExpr::AO__scoped_atomic_fetch_add:
1240 case AtomicExpr::AO__scoped_atomic_fetch_max:
1241 case AtomicExpr::AO__scoped_atomic_fetch_min:
1242 case AtomicExpr::AO__scoped_atomic_fetch_sub:
1243 case AtomicExpr::AO__scoped_atomic_add_fetch:
1244 case AtomicExpr::AO__scoped_atomic_max_fetch:
1245 case AtomicExpr::AO__scoped_atomic_min_fetch:
1246 case AtomicExpr::AO__scoped_atomic_sub_fetch:
1249 case AtomicExpr::AO__atomic_fetch_and:
1250 case AtomicExpr::AO__atomic_fetch_nand:
1251 case AtomicExpr::AO__atomic_fetch_or:
1252 case AtomicExpr::AO__atomic_fetch_xor:
1253 case AtomicExpr::AO__atomic_and_fetch:
1254 case AtomicExpr::AO__atomic_nand_fetch:
1255 case AtomicExpr::AO__atomic_or_fetch:
1256 case AtomicExpr::AO__atomic_xor_fetch:
1257 case AtomicExpr::AO__atomic_exchange_n:
1258 case AtomicExpr::AO__atomic_store_n:
1259 case AtomicExpr::AO__c11_atomic_fetch_and:
1260 case AtomicExpr::AO__c11_atomic_fetch_nand:
1261 case AtomicExpr::AO__c11_atomic_fetch_or:
1262 case AtomicExpr::AO__c11_atomic_fetch_xor:
1263 case AtomicExpr::AO__c11_atomic_exchange:
1264 case AtomicExpr::AO__c11_atomic_store:
1265 case AtomicExpr::AO__scoped_atomic_fetch_and:
1266 case AtomicExpr::AO__scoped_atomic_fetch_nand:
1267 case AtomicExpr::AO__scoped_atomic_fetch_or:
1268 case AtomicExpr::AO__scoped_atomic_fetch_xor:
1269 case AtomicExpr::AO__scoped_atomic_and_fetch:
1270 case AtomicExpr::AO__scoped_atomic_nand_fetch:
1271 case AtomicExpr::AO__scoped_atomic_or_fetch:
1272 case AtomicExpr::AO__scoped_atomic_xor_fetch:
1273 case AtomicExpr::AO__scoped_atomic_store_n:
1274 case AtomicExpr::AO__scoped_atomic_exchange_n:
1275 case AtomicExpr::AO__atomic_fetch_uinc:
1276 case AtomicExpr::AO__atomic_fetch_udec:
1277 case AtomicExpr::AO__scoped_atomic_fetch_uinc:
1278 case AtomicExpr::AO__scoped_atomic_fetch_udec:
1285 bool shouldCastToIntPtrTy =
1294 if (shouldCastToIntPtrTy) {
1295 ptr = atomics.castToAtomicIntPointer(ptr);
1297 val1 = atomics.convertToAtomicIntPointer(val1);
1299 val2 = atomics.convertToAtomicIntPointer(val2);
1302 if (shouldCastToIntPtrTy)
1303 dest = atomics.castToAtomicIntPointer(dest);
1306 }
else if (e->
getOp() == AtomicExpr::AO__atomic_test_and_set) {
1308 "test_and_set.bool");
1310 dest = atomics.createTempAlloca();
1311 if (shouldCastToIntPtrTy)
1312 dest = atomics.castToAtomicIntPointer(dest);
1315 bool powerOf2Size = (size & (size - 1)) == 0;
1316 bool useLibCall = !powerOf2Size || (size > 16);
1333 bool isStore = e->
getOp() == AtomicExpr::AO__c11_atomic_store ||
1334 e->
getOp() == AtomicExpr::AO__opencl_atomic_store ||
1335 e->
getOp() == AtomicExpr::AO__hip_atomic_store ||
1336 e->
getOp() == AtomicExpr::AO__atomic_store ||
1337 e->
getOp() == AtomicExpr::AO__atomic_store_n ||
1338 e->
getOp() == AtomicExpr::AO__scoped_atomic_store ||
1339 e->
getOp() == AtomicExpr::AO__scoped_atomic_store_n ||
1340 e->
getOp() == AtomicExpr::AO__atomic_clear;
1341 bool isLoad = e->
getOp() == AtomicExpr::AO__c11_atomic_load ||
1342 e->
getOp() == AtomicExpr::AO__opencl_atomic_load ||
1343 e->
getOp() == AtomicExpr::AO__hip_atomic_load ||
1344 e->
getOp() == AtomicExpr::AO__atomic_load ||
1345 e->
getOp() == AtomicExpr::AO__atomic_load_n ||
1346 e->
getOp() == AtomicExpr::AO__scoped_atomic_load ||
1347 e->
getOp() == AtomicExpr::AO__scoped_atomic_load_n;
1349 auto emitAtomicOpCallBackFn = [&](cir::MemOrder memOrder) {
1350 emitAtomicOp(*
this, e, dest, ptr, val1, val2, isWeakExpr, orderFailExpr,
1351 size, memOrder, scopeConst, scope);
1354 emitAtomicOpCallBackFn);
1367 return emitAtomicLoad(lvalue, loc, cir::MemOrder::SequentiallyConsistent,
1374 cir::MemOrder order,
bool isVolatile,
1376 AtomicInfo info(*
this, lvalue,
getLoc(loc));
1377 return info.emitAtomicLoad(slot, loc,
true, order, isVolatile);
1382 auto order = cir::MemOrder::SequentiallyConsistent;
1395 cir::MemOrder order,
bool isVolatile,
1399 mlir::Location loc = dest.
getPointer().getLoc();
1404 AtomicInfo atomics(*
this, dest, loc);
1405 LValue lvalue = atomics.getAtomicLValue();
1410 atomics.emitCopyIntoMemory(rvalue);
1415 if (atomics.shouldUseLibCall()) {
1417 cgm.errorNYI(loc,
"emitAtomicStore: atomic store with library call");
1422 mlir::Value valueToStore = atomics.convertRValueToInt(rvalue, loc);
1425 Address addr = atomics.getAtomicAddress();
1426 if (mlir::Value value = atomics.getScalarRValValueOrNull(rvalue)) {
1428 addr = atomics.castToAtomicIntPointer(addr);
1433 cir::StoreOp store = builder.createStore(loc, valueToStore, addr);
1438 store.setMemOrder(order);
1443 store.setIsVolatile(
true);
1449 cgm.errorNYI(loc,
"emitAtomicStore: non-simple atomic lvalue");
1456 switch (atomics.getEvaluationKind()) {
1472 bool zeroed =
false;
1474 zeroed = atomics.emitMemSetZeroIfNecessary();
1475 dest = atomics.projectValue();
1490 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 emitAtomicCmpXchgFailureSetCheckWeak(CIRGenFunction &cgf, AtomicExpr *e, Expr *isWeakExpr, Address dest, Address ptr, Address val1, Address val2, 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, uint64_t size, cir::MemOrder successOrder, cir::MemOrder failureOrder, cir::SyncScopeKind scope)
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 void emitAtomicExprWithDynamicMemOrder(CIRGenFunction &cgf, mlir::Value order, bool isStore, bool isLoad, bool isFence, llvm::function_ref< void(cir::MemOrder)> emitAtomicOpFn)
static void emitAtomicOp(CIRGenFunction &cgf, AtomicExpr *expr, Address dest, Address ptr, Address val1, Address val2, Expr *isWeakExpr, Expr *failureOrderExpr, int64_t size, cir::MemOrder order, cir::SyncScopeKind scope)
static void emitDefaultCaseLabel(CIRGenBuilderTy &builder, mlir::Location loc)
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 std::optional< cir::MemOrder > getEffectiveAtomicMemOrder(cir::MemOrder oriOrder, bool isStore, bool isLoad, bool isFence)
static void emitAtomicCmpXchgFailureSet(CIRGenFunction &cgf, AtomicExpr *e, bool isWeak, Address dest, Address ptr, Address val1, Address val2, Expr *failureOrderExpr, uint64_t size, cir::MemOrder successOrder, cir::SyncScopeKind scope)
*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.
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
Address withPointer(mlir::Value newPtr) const
Return address with different pointer, but same element type and alignment.
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
static AggValueSlot forLValue(const LValue &LV, IsDestructed_t isDestructed, IsAliased_t isAliased, Overlap_t mayOverlap, IsZeroed_t isZeroed=IsNotZeroed)
cir::StoreOp createStore(mlir::Location loc, mlir::Value val, Address dst, bool isVolatile=false, mlir::IntegerAttr align={}, cir::SyncScopeKindAttr scope={}, cir::MemOrderAttr order={})
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::LoadOp createLoad(mlir::Location loc, Address addr, bool isVolatile=false)
cir::IntType getUIntNTy(int n)
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...
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)
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.
const cir::CIRDataLayout getDataLayout() const
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.
CharUnits - This is an opaque type for sizes expressed in character units.
llvm::Align getAsAlign() const
getAsAlign - Returns Quantity as a valid llvm::Align, Beware llvm::Align assumes power of two 8-bit b...
QuantityType getQuantity() const
getQuantity - 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.
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
SyncScope
Defines sync scope values used internally by clang.
static bool atomicInfoGetAtomicPointer()
static bool aggValueSlotGC()
static bool opLoadStoreAtomic()
static bool opLoadStoreTbaa()
static bool atomicUseLibCall()
static bool atomicOpenMP()
static bool atomicMicrosoftVolatile()
static bool atomicSyncScopeID()
static bool atomicInfoGetAtomicAddress()
EvalResult is a struct with detailed info about an evaluated expression.
APValue Val
Val - This is the value the expression can be folded to.