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 CharUnits getAtomicAlignment()
const {
return atomicAlign; }
73 mlir::Value getAtomicPointer()
const {
74 if (lvalue.isSimple())
75 return lvalue.getPointer();
79 bool shouldUseLibCall()
const {
return useLibCall; }
80 const LValue &getAtomicLValue()
const {
return lvalue; }
81 Address getAtomicAddress()
const {
83 if (lvalue.isSimple()) {
84 elemTy = lvalue.getAddress().getElementType();
87 cgf.cgm.errorNYI(loc,
"AtomicInfo::getAtomicAddress: non-simple lvalue");
89 return Address(getAtomicPointer(), elemTy, getAtomicAlignment());
98 bool hasPadding()
const {
return (valueSizeInBits != atomicSizeInBits); }
100 bool emitMemSetZeroIfNecessary()
const;
102 mlir::Value getScalarRValValueOrNull(RValue rvalue)
const;
106 Address castToAtomicIntPointer(Address addr)
const;
111 Address convertToAtomicIntPointer(Address addr)
const;
114 mlir::Value convertRValueToInt(RValue rvalue,
bool cmpxchg =
false)
const;
116 RValue convertToValueOrAtomic(mlir::Value intVal, AggValueSlot resultSlot,
117 SourceLocation loc,
bool asValue,
118 bool cmpxchg =
false)
const;
121 void emitCopyIntoMemory(RValue rvalue)
const;
124 LValue projectValue()
const {
125 assert(lvalue.isSimple());
126 Address addr = getAtomicAddress();
128 cgf.cgm.errorNYI(loc,
"AtomicInfo::projectValue: padding");
132 return LValue::makeAddr(addr, getValueType(), lvalue.getBaseInfo());
137 RValue emitAtomicLoad(AggValueSlot resultSlot, SourceLocation loc,
138 bool asValue, cir::MemOrder order,
bool isVolatile);
141 Address createTempAlloca()
const;
144 bool requiresMemSetZero(mlir::Type ty)
const;
147 mlir::Value emitAtomicLoadOp(cir::MemOrder order,
bool isVolatile,
148 bool cmpxchg =
false);
164 uint64_t expectedSize) {
171bool AtomicInfo::requiresMemSetZero(mlir::Type ty)
const {
177 switch (getEvaluationKind()) {
184 mlir::cast<cir::ComplexType>(ty).getElementType(),
185 atomicSizeInBits / 2);
190 llvm_unreachable(
"bad evaluation kind");
193Address AtomicInfo::convertToAtomicIntPointer(Address addr)
const {
196 if (sourceSizeInBits != atomicSizeInBits) {
199 "AtomicInfo::convertToAtomicIntPointer: convert through temp alloca");
202 return castToAtomicIntPointer(addr);
205RValue AtomicInfo::emitAtomicLoad(AggValueSlot resultSlot, SourceLocation loc,
206 bool asValue, cir::MemOrder order,
209 if (shouldUseLibCall()) {
211 cgf.
cgm.
errorNYI(loc,
"emitAtomicLoad: emit atomic lib call");
216 mlir::Value loadOp = emitAtomicLoadOp(order, isVolatile);
224 return convertToValueOrAtomic(loadOp, resultSlot, loc, asValue);
227Address AtomicInfo::createTempAlloca()
const {
230 QualType tmpTy = (lvalue.isBitField() && valueSizeInBits > atomicSizeInBits)
234 cgf.
createMemTemp(tmpTy, getAtomicAlignment(), loc,
"atomic-temp");
237 if (lvalue.isBitField()) {
238 cgf.
cgm.
errorNYI(loc,
"AtomicInfo::createTempAlloca: bitfield lvalue");
244mlir::Value AtomicInfo::getScalarRValValueOrNull(RValue rvalue)
const {
245 if (rvalue.
isScalar() && (!hasPadding() || !lvalue.isSimple()))
250Address AtomicInfo::castToAtomicIntPointer(Address addr)
const {
253 if (intTy && intTy.getWidth() == atomicSizeInBits)
259bool AtomicInfo::emitMemSetZeroIfNecessary()
const {
260 assert(lvalue.isSimple());
261 Address addr = lvalue.getAddress();
266 "AtomicInfo::emitMemSetZeroIfNecaessary: emit memset zero");
276 if (cir::isAnyFloatingPointType(valueTy))
281mlir::Value AtomicInfo::emitAtomicLoadOp(cir::MemOrder order,
bool isVolatile,
283 Address addr = getAtomicAddress();
285 addr = castToAtomicIntPointer(addr);
289 op.setMemOrder(order);
295mlir::Value AtomicInfo::convertRValueToInt(RValue rvalue,
bool cmpxchg)
const {
298 if (mlir::Value value = getScalarRValValueOrNull(rvalue)) {
303 loc,
"AtomicInfo::convertRValueToInt: cast scalar rvalue to int");
308 loc,
"AtomicInfo::convertRValueToInt: cast non-scalar rvalue to int");
312RValue AtomicInfo::convertToValueOrAtomic(mlir::Value intVal,
313 AggValueSlot resultSlot,
314 SourceLocation loc,
bool asValue,
315 bool cmpxchg)
const {
317 assert((mlir::isa<cir::IntType, cir::PointerType, cir::FPTypeInterface>(
318 intVal.getType())) &&
319 "Expected integer, pointer or floating point value when converting "
322 !lvalue.isBitField() || lvalue.getBitFieldInfo().size == valueSizeInBits;
324 ((isWholeValue && !hasPadding()) || !asValue)) {
326 : getAtomicAddress().getElementType();
328 assert((!mlir::isa<cir::IntType>(valTy) || intVal.getType() == valTy) &&
329 "Different integer types.");
333 cgf.
cgm.
errorNYI(
"convertToValueOrAtomic: convert through bitcast");
337 cgf.
cgm.
errorNYI(
"convertToValueOrAtomic: convert through temp");
343void AtomicInfo::emitCopyIntoMemory(RValue rvalue)
const {
344 assert(lvalue.isSimple());
350 cgf.
cgm.
errorNYI(
"copying aggregate into atomic lvalue");
357 emitMemSetZeroIfNecessary();
360 LValue tempLValue = projectValue();
372 mlir::ArrayAttr valuesAttr = builder.getArrayAttr({});
373 mlir::OpBuilder::InsertPoint insertPoint;
374 cir::CaseOp::create(builder, loc, valuesAttr, cir::CaseOpKind::Default,
376 builder.restoreInsertionPoint(insertPoint);
382 mlir::Type orderType,
385 for (cir::MemOrder order : orders)
386 orderAttrs.push_back(cir::IntAttr::get(orderType,
static_cast<int>(order)));
387 mlir::ArrayAttr ordersAttr = builder.getArrayAttr(orderAttrs);
389 mlir::OpBuilder::InsertPoint insertPoint;
390 cir::CaseOp::create(builder, loc, ordersAttr, cir::CaseOpKind::Anyof,
392 builder.restoreInsertionPoint(insertPoint);
398 cir::MemOrder successOrder,
399 cir::MemOrder failureOrder,
400 cir::SyncScopeKind scope) {
404 mlir::Value expected = builder.
createLoad(loc, val1);
405 mlir::Value desired = builder.
createLoad(loc, val2);
407 auto cmpxchg = cir::AtomicCmpXchgOp::create(
416 cmpxchg.setWeak(isWeak);
418 mlir::Value failed = builder.
createNot(cmpxchg.getSuccess());
419 cir::IfOp::create(builder, loc, failed,
false,
420 [&](mlir::OpBuilder &, mlir::Location) {
421 auto ptrTy = mlir::cast<cir::PointerType>(
440 Expr *failureOrderExpr, uint64_t size,
441 cir::MemOrder successOrder,
442 cir::SyncScopeKind scope) {
445 uint64_t failureOrderInt = failureOrderEval.
Val.
getInt().getZExtValue();
447 cir::MemOrder failureOrder;
449 failureOrder = cir::MemOrder::Relaxed;
451 switch ((cir::MemOrder)failureOrderInt) {
452 case cir::MemOrder::Relaxed:
455 case cir::MemOrder::Release:
456 case cir::MemOrder::AcquireRelease:
457 failureOrder = cir::MemOrder::Relaxed;
459 case cir::MemOrder::Consume:
460 case cir::MemOrder::Acquire:
461 failureOrder = cir::MemOrder::Acquire;
463 case cir::MemOrder::SequentiallyConsistent:
464 failureOrder = cir::MemOrder::SequentiallyConsistent;
474 failureOrder, scope);
482 mlir::Value failureOrderVal = cgf.
emitScalarExpr(failureOrderExpr);
484 cir::SwitchOp::create(
486 [&](mlir::OpBuilder &
b, mlir::Location loc, mlir::OperationState &os) {
487 mlir::Block *switchBlock = cgf.getBuilder().getBlock();
499 emitDefaultCaseLabel(cgf.getBuilder(), atomicLoc);
500 emitAtomicCmpXchg(cgf, e, isWeak, dest, ptr, val1, val2, size,
501 successOrder, cir::MemOrder::Relaxed, scope);
502 cgf.getBuilder().createBreak(atomicLoc);
503 cgf.getBuilder().setInsertionPointToEnd(switchBlock);
507 emitMemOrderCaseLabel(cgf.getBuilder(), loc, failureOrderVal.getType(),
508 {cir::MemOrder::Consume, cir::MemOrder::Acquire});
510 successOrder, cir::MemOrder::Acquire, scope);
512 cgf.
getBuilder().setInsertionPointToEnd(switchBlock);
516 {cir::MemOrder::SequentiallyConsistent});
518 successOrder, cir::MemOrder::SequentiallyConsistent,
521 cgf.
getBuilder().setInsertionPointToEnd(switchBlock);
533 uint64_t size, cir::MemOrder successOrder, cir::SyncScopeKind scope) {
545 [&](mlir::OpBuilder &
b, mlir::Location loc) {
546 emitAtomicCmpXchgFailureSet(cgf, e, true, dest, ptr, val1,
547 val2, failureOrderExpr, size, successOrder,
549 cgf.getBuilder().createYield(atomicLoc);
551 [&](mlir::OpBuilder &
b, mlir::Location loc) {
552 emitAtomicCmpXchgFailureSet(cgf, e, false, dest, ptr, val1,
553 val2, failureOrderExpr, size, successOrder,
555 cgf.getBuilder().createYield(atomicLoc);
561 Expr *isWeakExpr,
Expr *failureOrderExpr, int64_t size,
562 cir::MemOrder order, cir::SyncScopeKind scope) {
564 llvm::StringRef opName;
567 mlir::Location loc = cgf.
getLoc(
expr->getSourceRange());
568 auto orderAttr = cir::MemOrderAttr::get(builder.getContext(), order);
569 auto scopeAttr = cir::SyncScopeKindAttr::get(builder.getContext(), scope);
570 cir::AtomicFetchKindAttr fetchAttr;
571 bool fetchFirst =
true;
573 auto handleFetchOp = [&](cir::AtomicFetchKind
kind) {
574 opName = cir::AtomicFetchOp::getOperationName();
575 fetchAttr = cir::AtomicFetchKindAttr::get(builder.getContext(),
kind);
578 switch (
expr->getOp()) {
579 case AtomicExpr::AO__c11_atomic_init:
580 llvm_unreachable(
"already handled!");
582 case AtomicExpr::AO__c11_atomic_compare_exchange_strong:
584 val2, failureOrderExpr, size, order, scope);
587 case AtomicExpr::AO__c11_atomic_compare_exchange_weak:
589 val2, failureOrderExpr, size, order, scope);
592 case AtomicExpr::AO__atomic_compare_exchange:
593 case AtomicExpr::AO__atomic_compare_exchange_n:
594 case AtomicExpr::AO__scoped_atomic_compare_exchange:
595 case AtomicExpr::AO__scoped_atomic_compare_exchange_n: {
599 failureOrderExpr, size, order, scope);
602 val1, val2, failureOrderExpr, size,
608 case AtomicExpr::AO__c11_atomic_load:
609 case AtomicExpr::AO__atomic_load_n:
610 case AtomicExpr::AO__atomic_load:
611 case AtomicExpr::AO__scoped_atomic_load_n:
612 case AtomicExpr::AO__scoped_atomic_load: {
616 load->setAttr(
"mem_order", orderAttr);
617 load->setAttr(
"sync_scope", scopeAttr);
619 builder.
createStore(loc, load->getResult(0), dest);
623 case AtomicExpr::AO__c11_atomic_store:
624 case AtomicExpr::AO__atomic_store_n:
625 case AtomicExpr::AO__atomic_store:
626 case AtomicExpr::AO__scoped_atomic_store:
627 case AtomicExpr::AO__scoped_atomic_store_n: {
628 cir::LoadOp loadVal1 = builder.
createLoad(loc, val1);
633 mlir::IntegerAttr{}, scopeAttr, orderAttr);
637 case AtomicExpr::AO__c11_atomic_exchange:
638 case AtomicExpr::AO__atomic_exchange_n:
639 case AtomicExpr::AO__atomic_exchange:
640 case AtomicExpr::AO__scoped_atomic_exchange_n:
641 case AtomicExpr::AO__scoped_atomic_exchange:
642 opName = cir::AtomicXchgOp::getOperationName();
645 case AtomicExpr::AO__atomic_add_fetch:
646 case AtomicExpr::AO__scoped_atomic_add_fetch:
649 case AtomicExpr::AO__c11_atomic_fetch_add:
650 case AtomicExpr::AO__atomic_fetch_add:
651 case AtomicExpr::AO__scoped_atomic_fetch_add:
652 handleFetchOp(cir::AtomicFetchKind::Add);
655 case AtomicExpr::AO__atomic_sub_fetch:
656 case AtomicExpr::AO__scoped_atomic_sub_fetch:
659 case AtomicExpr::AO__c11_atomic_fetch_sub:
660 case AtomicExpr::AO__atomic_fetch_sub:
661 case AtomicExpr::AO__scoped_atomic_fetch_sub:
662 handleFetchOp(cir::AtomicFetchKind::Sub);
665 case AtomicExpr::AO__atomic_min_fetch:
666 case AtomicExpr::AO__scoped_atomic_min_fetch:
669 case AtomicExpr::AO__c11_atomic_fetch_min:
670 case AtomicExpr::AO__atomic_fetch_min:
671 case AtomicExpr::AO__scoped_atomic_fetch_min:
672 handleFetchOp(cir::AtomicFetchKind::Min);
675 case AtomicExpr::AO__atomic_max_fetch:
676 case AtomicExpr::AO__scoped_atomic_max_fetch:
679 case AtomicExpr::AO__c11_atomic_fetch_max:
680 case AtomicExpr::AO__atomic_fetch_max:
681 case AtomicExpr::AO__scoped_atomic_fetch_max:
682 handleFetchOp(cir::AtomicFetchKind::Max);
685 case AtomicExpr::AO__atomic_and_fetch:
686 case AtomicExpr::AO__scoped_atomic_and_fetch:
689 case AtomicExpr::AO__c11_atomic_fetch_and:
690 case AtomicExpr::AO__atomic_fetch_and:
691 case AtomicExpr::AO__scoped_atomic_fetch_and:
692 handleFetchOp(cir::AtomicFetchKind::And);
695 case AtomicExpr::AO__atomic_or_fetch:
696 case AtomicExpr::AO__scoped_atomic_or_fetch:
699 case AtomicExpr::AO__c11_atomic_fetch_or:
700 case AtomicExpr::AO__atomic_fetch_or:
701 case AtomicExpr::AO__scoped_atomic_fetch_or:
702 handleFetchOp(cir::AtomicFetchKind::Or);
705 case AtomicExpr::AO__atomic_xor_fetch:
706 case AtomicExpr::AO__scoped_atomic_xor_fetch:
709 case AtomicExpr::AO__c11_atomic_fetch_xor:
710 case AtomicExpr::AO__atomic_fetch_xor:
711 case AtomicExpr::AO__scoped_atomic_fetch_xor:
712 handleFetchOp(cir::AtomicFetchKind::Xor);
715 case AtomicExpr::AO__atomic_nand_fetch:
716 case AtomicExpr::AO__scoped_atomic_nand_fetch:
719 case AtomicExpr::AO__c11_atomic_fetch_nand:
720 case AtomicExpr::AO__atomic_fetch_nand:
721 case AtomicExpr::AO__scoped_atomic_fetch_nand:
722 handleFetchOp(cir::AtomicFetchKind::Nand);
725 case AtomicExpr::AO__atomic_test_and_set: {
726 auto op = cir::AtomicTestAndSetOp::create(
734 case AtomicExpr::AO__atomic_clear: {
735 cir::AtomicClearOp::create(
742 case AtomicExpr::AO__atomic_fetch_uinc:
743 case AtomicExpr::AO__scoped_atomic_fetch_uinc:
744 handleFetchOp(cir::AtomicFetchKind::UIncWrap);
747 case AtomicExpr::AO__atomic_fetch_udec:
748 case AtomicExpr::AO__scoped_atomic_fetch_udec:
749 handleFetchOp(cir::AtomicFetchKind::UDecWrap);
752 case AtomicExpr::AO__opencl_atomic_init:
754 case AtomicExpr::AO__hip_atomic_compare_exchange_strong:
755 case AtomicExpr::AO__opencl_atomic_compare_exchange_strong:
757 case AtomicExpr::AO__opencl_atomic_compare_exchange_weak:
758 case AtomicExpr::AO__hip_atomic_compare_exchange_weak:
760 case AtomicExpr::AO__opencl_atomic_load:
761 case AtomicExpr::AO__hip_atomic_load:
763 case AtomicExpr::AO__opencl_atomic_store:
764 case AtomicExpr::AO__hip_atomic_store:
766 case AtomicExpr::AO__hip_atomic_exchange:
767 case AtomicExpr::AO__opencl_atomic_exchange:
769 case AtomicExpr::AO__hip_atomic_fetch_add:
770 case AtomicExpr::AO__opencl_atomic_fetch_add:
772 case AtomicExpr::AO__hip_atomic_fetch_sub:
773 case AtomicExpr::AO__opencl_atomic_fetch_sub:
775 case AtomicExpr::AO__hip_atomic_fetch_min:
776 case AtomicExpr::AO__opencl_atomic_fetch_min:
778 case AtomicExpr::AO__hip_atomic_fetch_max:
779 case AtomicExpr::AO__opencl_atomic_fetch_max:
781 case AtomicExpr::AO__hip_atomic_fetch_and:
782 case AtomicExpr::AO__opencl_atomic_fetch_and:
784 case AtomicExpr::AO__hip_atomic_fetch_or:
785 case AtomicExpr::AO__opencl_atomic_fetch_or:
787 case AtomicExpr::AO__hip_atomic_fetch_xor:
788 case AtomicExpr::AO__opencl_atomic_fetch_xor:
793 assert(!opName.empty() &&
"expected operation name to build");
794 mlir::Value loadVal1 = builder.
createLoad(loc, val1);
798 mlir::Operation *rmwOp = builder.create(loc, builder.getStringAttr(opName),
799 atomicOperands, atomicResTys);
802 rmwOp->setAttr(
"binop", fetchAttr);
803 rmwOp->setAttr(
"mem_order", orderAttr);
804 rmwOp->setAttr(
"sync_scope", scopeAttr);
805 if (
expr->isVolatile())
806 rmwOp->setAttr(
"is_volatile", builder.getUnitAttr());
807 if (fetchFirst && opName == cir::AtomicFetchOp::getOperationName())
808 rmwOp->setAttr(
"fetch_first", builder.getUnitAttr());
810 mlir::Value result = rmwOp->getResult(0);
821 return cir::SyncScopeKind::SingleThread;
823 return cir::SyncScopeKind::System;
825 return cir::SyncScopeKind::Device;
827 return cir::SyncScopeKind::Workgroup;
829 return cir::SyncScopeKind::Wavefront;
831 return cir::SyncScopeKind::Cluster;
834 return cir::SyncScopeKind::HIPSingleThread;
836 return cir::SyncScopeKind::HIPSystem;
838 return cir::SyncScopeKind::HIPAgent;
840 return cir::SyncScopeKind::HIPWorkgroup;
842 return cir::SyncScopeKind::HIPWavefront;
844 return cir::SyncScopeKind::HIPCluster;
847 return cir::SyncScopeKind::OpenCLWorkGroup;
849 return cir::SyncScopeKind::OpenCLDevice;
851 return cir::SyncScopeKind::OpenCLAllSVMDevices;
853 return cir::SyncScopeKind::OpenCLSubGroup;
856 llvm_unreachable(
"unhandled sync scope");
861 Expr *isWeakExpr,
Expr *failureOrderExpr, int64_t size,
863 const std::optional<Expr::EvalResult> &scopeConst,
864 mlir::Value scopeValue) {
865 std::unique_ptr<AtomicScopeModel> scopeModel =
expr->getScopeModel();
868 emitAtomicOp(cgf,
expr, dest, ptr, val1, val2, isWeakExpr, failureOrderExpr,
869 size, order, cir::SyncScopeKind::System);
873 if (scopeConst.has_value()) {
875 cgf,
expr->getScope()->getSourceRange(),
876 scopeModel->map(scopeConst->Val.getInt().getZExtValue()));
877 emitAtomicOp(cgf,
expr, dest, ptr, val1, val2, isWeakExpr, failureOrderExpr,
878 size, order, mappedScope);
885 mlir::Location loc = cgf.
getLoc(
expr->getSourceRange());
887 unsigned fallback = scopeModel->getFallBackValue();
889 cir::SwitchOp::create(
890 builder, loc, scopeValue,
891 [&](mlir::OpBuilder &, mlir::Location loc, mlir::OperationState &) {
892 mlir::Block *switchBlock = builder.getBlock();
896 cgf,
expr->getScope()->getSourceRange(), scopeModel->map(fallback));
899 failureOrderExpr, size, order, fallbackScope);
901 builder.setInsertionPointToEnd(switchBlock);
904 for (
unsigned scope : allScopes) {
905 if (scope == fallback)
909 cgf,
expr->getScope()->getSourceRange(), scopeModel->map(scope));
911 mlir::ArrayAttr casesAttr = builder.getArrayAttr(
912 {cir::IntAttr::get(scopeValue.getType(), scope)});
913 mlir::OpBuilder::InsertPoint insertPoint;
914 cir::CaseOp::create(builder, loc, casesAttr, cir::CaseOpKind::Equal,
917 builder.restoreInsertionPoint(insertPoint);
919 failureOrderExpr, size, order, cirScope);
921 builder.setInsertionPointToEnd(switchBlock);
928static std::optional<cir::MemOrder>
938 if (oriOrder == cir::MemOrder::Consume ||
939 oriOrder == cir::MemOrder::Acquire ||
940 oriOrder == cir::MemOrder::AcquireRelease)
943 if (oriOrder == cir::MemOrder::Release ||
944 oriOrder == cir::MemOrder::AcquireRelease)
946 }
else if (isFence) {
947 if (oriOrder == cir::MemOrder::Relaxed)
952 if (oriOrder == cir::MemOrder::Consume)
953 return cir::MemOrder::Acquire;
958 CIRGenFunction &cgf, mlir::Value order,
bool isStore,
bool isLoad,
959 bool isFence, llvm::function_ref<
void(cir::MemOrder)> emitAtomicOpFn) {
967 cir::SwitchOp::create(
968 builder, order.getLoc(), order,
969 [&](mlir::OpBuilder &, mlir::Location loc, mlir::OperationState &) {
970 mlir::Block *switchBlock = builder.getBlock();
972 auto emitMemOrderCase = [&](llvm::ArrayRef<cir::MemOrder> caseOrders) {
974 for (int i = 1, e = caseOrders.size(); i < e; i++)
975 assert((getEffectiveAtomicMemOrder(caseOrders[i - 1], isStore,
977 getEffectiveAtomicMemOrder(caseOrders[i], isStore, isLoad,
979 "Effective memory order must be same!");
981 if (caseOrders.empty()) {
982 emitDefaultCaseLabel(builder, loc);
986 emitAtomicOpFn(cir::MemOrder::Relaxed);
987 } else if (std::optional<cir::MemOrder> actualOrder =
988 getEffectiveAtomicMemOrder(caseOrders[0], isStore,
991 if (!isFence && actualOrder == cir::MemOrder::Relaxed)
996 emitMemOrderCaseLabel(builder, loc, order.getType(), caseOrders);
997 emitAtomicOpFn(actualOrder.value());
1002 builder.createBreak(loc);
1003 builder.setInsertionPointToEnd(switchBlock);
1006 emitMemOrderCase( {});
1007 emitMemOrderCase({cir::MemOrder::Relaxed});
1008 emitMemOrderCase({cir::MemOrder::Consume, cir::MemOrder::Acquire});
1009 emitMemOrderCase({cir::MemOrder::Release});
1010 emitMemOrderCase({cir::MemOrder::AcquireRelease});
1011 emitMemOrderCase({cir::MemOrder::SequentiallyConsistent});
1018 const Expr *memOrder,
bool isStore,
bool isLoad,
bool isFence,
1019 llvm::function_ref<
void(cir::MemOrder)> emitAtomicOpFn) {
1023 uint64_t constOrder = eval.
Val.
getInt().getZExtValue();
1028 cir::MemOrder oriOrder =
static_cast<cir::MemOrder
>(constOrder);
1029 if (std::optional<cir::MemOrder> actualOrder =
1031 emitAtomicOpFn(actualOrder.value());
1046 memTy = ty->getValueType();
1048 Expr *isWeakExpr =
nullptr;
1049 Expr *orderFailExpr =
nullptr;
1057 if (e->
getOp() == AtomicExpr::AO__c11_atomic_init) {
1069 std::optional<Expr::EvalResult> scopeConst;
1072 scopeConst.emplace(std::move(eval));
1074 switch (e->
getOp()) {
1079 case AtomicExpr::AO__c11_atomic_init:
1080 llvm_unreachable(
"already handled above with emitAtomicInit");
1082 case AtomicExpr::AO__atomic_load_n:
1083 case AtomicExpr::AO__scoped_atomic_load_n:
1084 case AtomicExpr::AO__c11_atomic_load:
1085 case AtomicExpr::AO__atomic_test_and_set:
1086 case AtomicExpr::AO__atomic_clear:
1089 case AtomicExpr::AO__atomic_load:
1090 case AtomicExpr::AO__scoped_atomic_load:
1094 case AtomicExpr::AO__atomic_store:
1095 case AtomicExpr::AO__scoped_atomic_store:
1099 case AtomicExpr::AO__atomic_exchange:
1100 case AtomicExpr::AO__scoped_atomic_exchange:
1105 case AtomicExpr::AO__atomic_compare_exchange:
1106 case AtomicExpr::AO__atomic_compare_exchange_n:
1107 case AtomicExpr::AO__c11_atomic_compare_exchange_weak:
1108 case AtomicExpr::AO__c11_atomic_compare_exchange_strong:
1109 case AtomicExpr::AO__scoped_atomic_compare_exchange:
1110 case AtomicExpr::AO__scoped_atomic_compare_exchange_n:
1112 if (e->
getOp() == AtomicExpr::AO__atomic_compare_exchange ||
1113 e->
getOp() == AtomicExpr::AO__scoped_atomic_compare_exchange)
1118 if (e->
getOp() == AtomicExpr::AO__atomic_compare_exchange_n ||
1119 e->
getOp() == AtomicExpr::AO__atomic_compare_exchange ||
1120 e->
getOp() == AtomicExpr::AO__scoped_atomic_compare_exchange_n ||
1121 e->
getOp() == AtomicExpr::AO__scoped_atomic_compare_exchange)
1125 case AtomicExpr::AO__c11_atomic_fetch_add:
1126 case AtomicExpr::AO__c11_atomic_fetch_sub:
1137 mlir::Value scale = builder.getConstInt(loc, val1Scalar.getType(),
1139 val1Scalar = builder.createMul(loc, val1Scalar, scale);
1145 case AtomicExpr::AO__atomic_fetch_add:
1146 case AtomicExpr::AO__atomic_fetch_sub:
1147 case AtomicExpr::AO__atomic_add_fetch:
1148 case AtomicExpr::AO__atomic_sub_fetch:
1158 case AtomicExpr::AO__atomic_fetch_max:
1159 case AtomicExpr::AO__atomic_fetch_min:
1160 case AtomicExpr::AO__atomic_max_fetch:
1161 case AtomicExpr::AO__atomic_min_fetch:
1162 case AtomicExpr::AO__c11_atomic_fetch_max:
1163 case AtomicExpr::AO__c11_atomic_fetch_min:
1164 case AtomicExpr::AO__scoped_atomic_fetch_add:
1165 case AtomicExpr::AO__scoped_atomic_fetch_max:
1166 case AtomicExpr::AO__scoped_atomic_fetch_min:
1167 case AtomicExpr::AO__scoped_atomic_fetch_sub:
1168 case AtomicExpr::AO__scoped_atomic_add_fetch:
1169 case AtomicExpr::AO__scoped_atomic_max_fetch:
1170 case AtomicExpr::AO__scoped_atomic_min_fetch:
1171 case AtomicExpr::AO__scoped_atomic_sub_fetch:
1174 case AtomicExpr::AO__atomic_fetch_and:
1175 case AtomicExpr::AO__atomic_fetch_nand:
1176 case AtomicExpr::AO__atomic_fetch_or:
1177 case AtomicExpr::AO__atomic_fetch_xor:
1178 case AtomicExpr::AO__atomic_and_fetch:
1179 case AtomicExpr::AO__atomic_nand_fetch:
1180 case AtomicExpr::AO__atomic_or_fetch:
1181 case AtomicExpr::AO__atomic_xor_fetch:
1182 case AtomicExpr::AO__atomic_exchange_n:
1183 case AtomicExpr::AO__atomic_store_n:
1184 case AtomicExpr::AO__c11_atomic_fetch_and:
1185 case AtomicExpr::AO__c11_atomic_fetch_nand:
1186 case AtomicExpr::AO__c11_atomic_fetch_or:
1187 case AtomicExpr::AO__c11_atomic_fetch_xor:
1188 case AtomicExpr::AO__c11_atomic_exchange:
1189 case AtomicExpr::AO__c11_atomic_store:
1190 case AtomicExpr::AO__scoped_atomic_fetch_and:
1191 case AtomicExpr::AO__scoped_atomic_fetch_nand:
1192 case AtomicExpr::AO__scoped_atomic_fetch_or:
1193 case AtomicExpr::AO__scoped_atomic_fetch_xor:
1194 case AtomicExpr::AO__scoped_atomic_and_fetch:
1195 case AtomicExpr::AO__scoped_atomic_nand_fetch:
1196 case AtomicExpr::AO__scoped_atomic_or_fetch:
1197 case AtomicExpr::AO__scoped_atomic_xor_fetch:
1198 case AtomicExpr::AO__scoped_atomic_store_n:
1199 case AtomicExpr::AO__scoped_atomic_exchange_n:
1200 case AtomicExpr::AO__atomic_fetch_uinc:
1201 case AtomicExpr::AO__atomic_fetch_udec:
1202 case AtomicExpr::AO__scoped_atomic_fetch_uinc:
1203 case AtomicExpr::AO__scoped_atomic_fetch_udec:
1210 bool shouldCastToIntPtrTy =
1219 if (shouldCastToIntPtrTy) {
1220 ptr = atomics.castToAtomicIntPointer(ptr);
1222 val1 = atomics.convertToAtomicIntPointer(val1);
1224 val2 = atomics.convertToAtomicIntPointer(val2);
1227 if (shouldCastToIntPtrTy)
1228 dest = atomics.castToAtomicIntPointer(dest);
1231 }
else if (e->
getOp() == AtomicExpr::AO__atomic_test_and_set) {
1233 "test_and_set.bool");
1235 dest = atomics.createTempAlloca();
1236 if (shouldCastToIntPtrTy)
1237 dest = atomics.castToAtomicIntPointer(dest);
1240 bool powerOf2Size = (size & (size - 1)) == 0;
1241 bool useLibCall = !powerOf2Size || (size > 16);
1258 bool isStore = e->
getOp() == AtomicExpr::AO__c11_atomic_store ||
1259 e->
getOp() == AtomicExpr::AO__opencl_atomic_store ||
1260 e->
getOp() == AtomicExpr::AO__hip_atomic_store ||
1261 e->
getOp() == AtomicExpr::AO__atomic_store ||
1262 e->
getOp() == AtomicExpr::AO__atomic_store_n ||
1263 e->
getOp() == AtomicExpr::AO__scoped_atomic_store ||
1264 e->
getOp() == AtomicExpr::AO__scoped_atomic_store_n ||
1265 e->
getOp() == AtomicExpr::AO__atomic_clear;
1266 bool isLoad = e->
getOp() == AtomicExpr::AO__c11_atomic_load ||
1267 e->
getOp() == AtomicExpr::AO__opencl_atomic_load ||
1268 e->
getOp() == AtomicExpr::AO__hip_atomic_load ||
1269 e->
getOp() == AtomicExpr::AO__atomic_load ||
1270 e->
getOp() == AtomicExpr::AO__atomic_load_n ||
1271 e->
getOp() == AtomicExpr::AO__scoped_atomic_load ||
1272 e->
getOp() == AtomicExpr::AO__scoped_atomic_load_n;
1274 auto emitAtomicOpCallBackFn = [&](cir::MemOrder memOrder) {
1275 emitAtomicOp(*
this, e, dest, ptr, val1, val2, isWeakExpr, orderFailExpr,
1276 size, memOrder, scopeConst, scope);
1279 emitAtomicOpCallBackFn);
1292 return emitAtomicLoad(lvalue, loc, cir::MemOrder::SequentiallyConsistent,
1299 cir::MemOrder order,
bool isVolatile,
1301 AtomicInfo info(*
this, lvalue,
getLoc(loc));
1302 return info.emitAtomicLoad(slot, loc,
true, order, isVolatile);
1307 auto order = cir::MemOrder::SequentiallyConsistent;
1320 cir::MemOrder order,
bool isVolatile,
1324 mlir::Location loc = dest.
getPointer().getLoc();
1329 AtomicInfo atomics(*
this, dest, loc);
1330 LValue lvalue = atomics.getAtomicLValue();
1335 atomics.emitCopyIntoMemory(rvalue);
1340 if (atomics.shouldUseLibCall()) {
1342 cgm.errorNYI(loc,
"emitAtomicStore: atomic store with library call");
1347 mlir::Value valueToStore = atomics.convertRValueToInt(rvalue);
1350 Address addr = atomics.getAtomicAddress();
1351 if (mlir::Value value = atomics.getScalarRValValueOrNull(rvalue)) {
1353 addr = atomics.castToAtomicIntPointer(addr);
1358 cir::StoreOp store = builder.createStore(loc, valueToStore, addr);
1363 store.setMemOrder(order);
1368 store.setIsVolatile(
true);
1374 cgm.errorNYI(loc,
"emitAtomicStore: non-simple atomic lvalue");
1381 switch (atomics.getEvaluationKind()) {
1397 bool zeroed =
false;
1399 zeroed = atomics.emitMemSetZeroIfNecessary();
1400 dest = atomics.projectValue();
1415 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::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.