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;
117 void emitCopyIntoMemory(RValue rvalue)
const;
120 LValue projectValue()
const {
121 assert(lvalue.isSimple());
122 Address addr = getAtomicAddress();
124 cgf.cgm.errorNYI(loc,
"AtomicInfo::projectValue: padding");
128 return LValue::makeAddr(addr, getValueType(), lvalue.getBaseInfo());
132 Address createTempAlloca()
const;
135 bool requiresMemSetZero(mlir::Type ty)
const;
151 uint64_t expectedSize) {
158bool AtomicInfo::requiresMemSetZero(mlir::Type ty)
const {
164 switch (getEvaluationKind()) {
171 mlir::cast<cir::ComplexType>(ty).getElementType(),
172 atomicSizeInBits / 2);
177 llvm_unreachable(
"bad evaluation kind");
180Address AtomicInfo::convertToAtomicIntPointer(Address addr)
const {
183 if (sourceSizeInBits != atomicSizeInBits) {
186 "AtomicInfo::convertToAtomicIntPointer: convert through temp alloca");
189 return castToAtomicIntPointer(addr);
192Address AtomicInfo::createTempAlloca()
const {
194 (lvalue.isBitField() && valueSizeInBits > atomicSizeInBits) ? valueTy
196 getAtomicAlignment(), loc,
"atomic-temp");
199 if (lvalue.isBitField()) {
200 cgf.
cgm.
errorNYI(loc,
"AtomicInfo::createTempAlloca: bitfield lvalue");
206mlir::Value AtomicInfo::getScalarRValValueOrNull(RValue rvalue)
const {
207 if (rvalue.
isScalar() && (!hasPadding() || !lvalue.isSimple()))
212Address AtomicInfo::castToAtomicIntPointer(Address addr)
const {
215 if (intTy && intTy.getWidth() == atomicSizeInBits)
221bool AtomicInfo::emitMemSetZeroIfNecessary()
const {
222 assert(lvalue.isSimple());
223 Address addr = lvalue.getAddress();
228 "AtomicInfo::emitMemSetZeroIfNecaessary: emit memset zero");
238 if (cir::isAnyFloatingPointType(valueTy))
243mlir::Value AtomicInfo::convertRValueToInt(RValue rvalue,
bool cmpxchg)
const {
246 if (mlir::Value value = getScalarRValValueOrNull(rvalue)) {
251 loc,
"AtomicInfo::convertRValueToInt: cast scalar rvalue to int");
256 loc,
"AtomicInfo::convertRValueToInt: cast non-scalar rvalue to int");
262void AtomicInfo::emitCopyIntoMemory(RValue rvalue)
const {
263 assert(lvalue.isSimple());
269 cgf.
cgm.
errorNYI(
"copying aggregate into atomic lvalue");
276 emitMemSetZeroIfNecessary();
279 LValue tempLValue = projectValue();
285 cgf.
cgm.
errorNYI(
"copying complex into atomic lvalue");
290 mlir::Location loc) {
291 mlir::ArrayAttr ordersAttr = builder.getArrayAttr({});
292 mlir::OpBuilder::InsertPoint insertPoint;
293 cir::CaseOp::create(builder, loc, ordersAttr, cir::CaseOpKind::Default,
295 builder.restoreInsertionPoint(insertPoint);
301 mlir::Type orderType,
304 for (cir::MemOrder order : orders)
305 orderAttrs.push_back(cir::IntAttr::get(orderType,
static_cast<int>(order)));
306 mlir::ArrayAttr ordersAttr = builder.getArrayAttr(orderAttrs);
308 mlir::OpBuilder::InsertPoint insertPoint;
309 cir::CaseOp::create(builder, loc, ordersAttr, cir::CaseOpKind::Anyof,
311 builder.restoreInsertionPoint(insertPoint);
317 cir::MemOrder successOrder,
318 cir::MemOrder failureOrder,
319 cir::SyncScopeKind scope) {
323 mlir::Value expected = builder.
createLoad(loc, val1);
324 mlir::Value desired = builder.
createLoad(loc, val2);
326 auto cmpxchg = cir::AtomicCmpXchgOp::create(
335 cmpxchg.setWeak(isWeak);
337 mlir::Value failed = builder.
createNot(cmpxchg.getSuccess());
338 cir::IfOp::create(builder, loc, failed,
false,
339 [&](mlir::OpBuilder &, mlir::Location) {
340 auto ptrTy = mlir::cast<cir::PointerType>(
359 Expr *failureOrderExpr, uint64_t size,
360 cir::MemOrder successOrder,
361 cir::SyncScopeKind scope) {
364 uint64_t failureOrderInt = failureOrderEval.
Val.
getInt().getZExtValue();
366 cir::MemOrder failureOrder;
368 failureOrder = cir::MemOrder::Relaxed;
370 switch ((cir::MemOrder)failureOrderInt) {
371 case cir::MemOrder::Relaxed:
374 case cir::MemOrder::Release:
375 case cir::MemOrder::AcquireRelease:
376 failureOrder = cir::MemOrder::Relaxed;
378 case cir::MemOrder::Consume:
379 case cir::MemOrder::Acquire:
380 failureOrder = cir::MemOrder::Acquire;
382 case cir::MemOrder::SequentiallyConsistent:
383 failureOrder = cir::MemOrder::SequentiallyConsistent;
393 failureOrder, scope);
401 mlir::Value failureOrderVal = cgf.
emitScalarExpr(failureOrderExpr);
403 cir::SwitchOp::create(
405 [&](mlir::OpBuilder &
b, mlir::Location loc, mlir::OperationState &os) {
406 mlir::Block *switchBlock = cgf.getBuilder().getBlock();
418 emitMemOrderDefaultCaseLabel(cgf.getBuilder(), atomicLoc);
419 emitAtomicCmpXchg(cgf, e, isWeak, dest, ptr, val1, val2, size,
420 successOrder, cir::MemOrder::Relaxed, scope);
421 cgf.getBuilder().createBreak(atomicLoc);
422 cgf.getBuilder().setInsertionPointToEnd(switchBlock);
426 emitMemOrderCaseLabel(cgf.getBuilder(), loc, failureOrderVal.getType(),
427 {cir::MemOrder::Consume, cir::MemOrder::Acquire});
429 successOrder, cir::MemOrder::Acquire, scope);
431 cgf.
getBuilder().setInsertionPointToEnd(switchBlock);
435 {cir::MemOrder::SequentiallyConsistent});
437 successOrder, cir::MemOrder::SequentiallyConsistent,
440 cgf.
getBuilder().setInsertionPointToEnd(switchBlock);
448 Expr *isWeakExpr,
Expr *failureOrderExpr, int64_t size,
449 cir::MemOrder order, cir::SyncScopeKind scope) {
451 llvm::StringRef opName;
454 mlir::Location loc = cgf.
getLoc(
expr->getSourceRange());
455 auto orderAttr = cir::MemOrderAttr::get(builder.getContext(), order);
456 auto scopeAttr = cir::SyncScopeKindAttr::get(builder.getContext(), scope);
457 cir::AtomicFetchKindAttr fetchAttr;
458 bool fetchFirst =
true;
460 switch (
expr->getOp()) {
461 case AtomicExpr::AO__c11_atomic_init:
462 llvm_unreachable(
"already handled!");
464 case AtomicExpr::AO__c11_atomic_compare_exchange_strong:
466 val2, failureOrderExpr, size, order, scope);
469 case AtomicExpr::AO__c11_atomic_compare_exchange_weak:
471 val2, failureOrderExpr, size, order, scope);
474 case AtomicExpr::AO__atomic_compare_exchange:
475 case AtomicExpr::AO__atomic_compare_exchange_n:
476 case AtomicExpr::AO__scoped_atomic_compare_exchange:
477 case AtomicExpr::AO__scoped_atomic_compare_exchange_n: {
481 failureOrderExpr, size, order, scope);
485 "emitAtomicOp: non-constant isWeak");
490 case AtomicExpr::AO__c11_atomic_load:
491 case AtomicExpr::AO__atomic_load_n:
492 case AtomicExpr::AO__atomic_load:
493 case AtomicExpr::AO__scoped_atomic_load_n:
494 case AtomicExpr::AO__scoped_atomic_load: {
498 load->setAttr(
"mem_order", orderAttr);
499 load->setAttr(
"sync_scope", scopeAttr);
501 builder.
createStore(loc, load->getResult(0), dest);
505 case AtomicExpr::AO__c11_atomic_store:
506 case AtomicExpr::AO__atomic_store_n:
507 case AtomicExpr::AO__atomic_store:
508 case AtomicExpr::AO__scoped_atomic_store:
509 case AtomicExpr::AO__scoped_atomic_store_n: {
510 cir::LoadOp loadVal1 = builder.
createLoad(loc, val1);
515 mlir::IntegerAttr{}, scopeAttr, orderAttr);
519 case AtomicExpr::AO__c11_atomic_exchange:
520 case AtomicExpr::AO__atomic_exchange_n:
521 case AtomicExpr::AO__atomic_exchange:
522 case AtomicExpr::AO__scoped_atomic_exchange_n:
523 case AtomicExpr::AO__scoped_atomic_exchange:
524 opName = cir::AtomicXchgOp::getOperationName();
527 case AtomicExpr::AO__atomic_add_fetch:
528 case AtomicExpr::AO__scoped_atomic_add_fetch:
531 case AtomicExpr::AO__c11_atomic_fetch_add:
532 case AtomicExpr::AO__atomic_fetch_add:
533 case AtomicExpr::AO__scoped_atomic_fetch_add:
534 opName = cir::AtomicFetchOp::getOperationName();
535 fetchAttr = cir::AtomicFetchKindAttr::get(builder.getContext(),
536 cir::AtomicFetchKind::Add);
539 case AtomicExpr::AO__atomic_sub_fetch:
540 case AtomicExpr::AO__scoped_atomic_sub_fetch:
543 case AtomicExpr::AO__c11_atomic_fetch_sub:
544 case AtomicExpr::AO__atomic_fetch_sub:
545 case AtomicExpr::AO__scoped_atomic_fetch_sub:
546 opName = cir::AtomicFetchOp::getOperationName();
547 fetchAttr = cir::AtomicFetchKindAttr::get(builder.getContext(),
548 cir::AtomicFetchKind::Sub);
551 case AtomicExpr::AO__atomic_min_fetch:
552 case AtomicExpr::AO__scoped_atomic_min_fetch:
555 case AtomicExpr::AO__c11_atomic_fetch_min:
556 case AtomicExpr::AO__atomic_fetch_min:
557 case AtomicExpr::AO__scoped_atomic_fetch_min:
558 opName = cir::AtomicFetchOp::getOperationName();
559 fetchAttr = cir::AtomicFetchKindAttr::get(builder.getContext(),
560 cir::AtomicFetchKind::Min);
563 case AtomicExpr::AO__atomic_max_fetch:
564 case AtomicExpr::AO__scoped_atomic_max_fetch:
567 case AtomicExpr::AO__c11_atomic_fetch_max:
568 case AtomicExpr::AO__atomic_fetch_max:
569 case AtomicExpr::AO__scoped_atomic_fetch_max:
570 opName = cir::AtomicFetchOp::getOperationName();
571 fetchAttr = cir::AtomicFetchKindAttr::get(builder.getContext(),
572 cir::AtomicFetchKind::Max);
575 case AtomicExpr::AO__atomic_and_fetch:
576 case AtomicExpr::AO__scoped_atomic_and_fetch:
579 case AtomicExpr::AO__c11_atomic_fetch_and:
580 case AtomicExpr::AO__atomic_fetch_and:
581 case AtomicExpr::AO__scoped_atomic_fetch_and:
582 opName = cir::AtomicFetchOp::getOperationName();
583 fetchAttr = cir::AtomicFetchKindAttr::get(builder.getContext(),
584 cir::AtomicFetchKind::And);
587 case AtomicExpr::AO__atomic_or_fetch:
588 case AtomicExpr::AO__scoped_atomic_or_fetch:
591 case AtomicExpr::AO__c11_atomic_fetch_or:
592 case AtomicExpr::AO__atomic_fetch_or:
593 case AtomicExpr::AO__scoped_atomic_fetch_or:
594 opName = cir::AtomicFetchOp::getOperationName();
595 fetchAttr = cir::AtomicFetchKindAttr::get(builder.getContext(),
596 cir::AtomicFetchKind::Or);
599 case AtomicExpr::AO__atomic_xor_fetch:
600 case AtomicExpr::AO__scoped_atomic_xor_fetch:
603 case AtomicExpr::AO__c11_atomic_fetch_xor:
604 case AtomicExpr::AO__atomic_fetch_xor:
605 case AtomicExpr::AO__scoped_atomic_fetch_xor:
606 opName = cir::AtomicFetchOp::getOperationName();
607 fetchAttr = cir::AtomicFetchKindAttr::get(builder.getContext(),
608 cir::AtomicFetchKind::Xor);
611 case AtomicExpr::AO__atomic_nand_fetch:
612 case AtomicExpr::AO__scoped_atomic_nand_fetch:
615 case AtomicExpr::AO__c11_atomic_fetch_nand:
616 case AtomicExpr::AO__atomic_fetch_nand:
617 case AtomicExpr::AO__scoped_atomic_fetch_nand:
618 opName = cir::AtomicFetchOp::getOperationName();
619 fetchAttr = cir::AtomicFetchKindAttr::get(builder.getContext(),
620 cir::AtomicFetchKind::Nand);
623 case AtomicExpr::AO__atomic_test_and_set: {
624 auto op = cir::AtomicTestAndSetOp::create(
632 case AtomicExpr::AO__atomic_clear: {
633 cir::AtomicClearOp::create(
640 case AtomicExpr::AO__opencl_atomic_init:
642 case AtomicExpr::AO__hip_atomic_compare_exchange_strong:
643 case AtomicExpr::AO__opencl_atomic_compare_exchange_strong:
645 case AtomicExpr::AO__opencl_atomic_compare_exchange_weak:
646 case AtomicExpr::AO__hip_atomic_compare_exchange_weak:
648 case AtomicExpr::AO__opencl_atomic_load:
649 case AtomicExpr::AO__hip_atomic_load:
651 case AtomicExpr::AO__opencl_atomic_store:
652 case AtomicExpr::AO__hip_atomic_store:
654 case AtomicExpr::AO__hip_atomic_exchange:
655 case AtomicExpr::AO__opencl_atomic_exchange:
657 case AtomicExpr::AO__hip_atomic_fetch_add:
658 case AtomicExpr::AO__opencl_atomic_fetch_add:
660 case AtomicExpr::AO__hip_atomic_fetch_sub:
661 case AtomicExpr::AO__opencl_atomic_fetch_sub:
663 case AtomicExpr::AO__hip_atomic_fetch_min:
664 case AtomicExpr::AO__opencl_atomic_fetch_min:
666 case AtomicExpr::AO__hip_atomic_fetch_max:
667 case AtomicExpr::AO__opencl_atomic_fetch_max:
669 case AtomicExpr::AO__hip_atomic_fetch_and:
670 case AtomicExpr::AO__opencl_atomic_fetch_and:
672 case AtomicExpr::AO__hip_atomic_fetch_or:
673 case AtomicExpr::AO__opencl_atomic_fetch_or:
675 case AtomicExpr::AO__hip_atomic_fetch_xor:
676 case AtomicExpr::AO__opencl_atomic_fetch_xor:
678 case AtomicExpr::AO__scoped_atomic_fetch_uinc:
679 case AtomicExpr::AO__scoped_atomic_fetch_udec:
680 case AtomicExpr::AO__atomic_fetch_uinc:
681 case AtomicExpr::AO__atomic_fetch_udec:
686 assert(!opName.empty() &&
"expected operation name to build");
687 mlir::Value loadVal1 = builder.
createLoad(loc, val1);
691 mlir::Operation *rmwOp = builder.create(loc, builder.getStringAttr(opName),
692 atomicOperands, atomicResTys);
695 rmwOp->setAttr(
"binop", fetchAttr);
696 rmwOp->setAttr(
"mem_order", orderAttr);
697 rmwOp->setAttr(
"sync_scope", scopeAttr);
698 if (
expr->isVolatile())
699 rmwOp->setAttr(
"is_volatile", builder.getUnitAttr());
700 if (fetchFirst && opName == cir::AtomicFetchOp::getOperationName())
701 rmwOp->setAttr(
"fetch_first", builder.getUnitAttr());
703 mlir::Value result = rmwOp->getResult(0);
714 cgf.
cgm.
errorNYI(range,
"convertSyncScopeToCIR: unhandled sync scope");
715 return cir::SyncScopeKind::System;
719 return cir::SyncScopeKind::SingleThread;
721 return cir::SyncScopeKind::System;
727 Expr *isWeakExpr,
Expr *failureOrderExpr, int64_t size,
729 const std::optional<Expr::EvalResult> &scopeConst,
730 mlir::Value scopeValue) {
731 std::unique_ptr<AtomicScopeModel> scopeModel =
expr->getScopeModel();
734 emitAtomicOp(cgf,
expr, dest, ptr, val1, val2, isWeakExpr, failureOrderExpr,
735 size, order, cir::SyncScopeKind::System);
739 if (scopeConst.has_value()) {
741 cgf,
expr->getScope()->getSourceRange(),
742 scopeModel->map(scopeConst->Val.getInt().getZExtValue()));
743 emitAtomicOp(cgf,
expr, dest, ptr, val1, val2, isWeakExpr, failureOrderExpr,
744 size, order, mappedScope);
749 cgf.
cgm.
errorNYI(
expr->getSourceRange(),
"emitAtomicOp: dynamic sync scope");
752static std::optional<cir::MemOrder>
762 if (oriOrder == cir::MemOrder::Consume ||
763 oriOrder == cir::MemOrder::Acquire ||
764 oriOrder == cir::MemOrder::AcquireRelease)
767 if (oriOrder == cir::MemOrder::Release ||
768 oriOrder == cir::MemOrder::AcquireRelease)
770 }
else if (isFence) {
771 if (oriOrder == cir::MemOrder::Relaxed)
776 if (oriOrder == cir::MemOrder::Consume)
777 return cir::MemOrder::Acquire;
782 CIRGenFunction &cgf, mlir::Value order,
bool isStore,
bool isLoad,
783 bool isFence, llvm::function_ref<
void(cir::MemOrder)> emitAtomicOpFn) {
791 cir::SwitchOp::create(
792 builder, order.getLoc(), order,
793 [&](mlir::OpBuilder &, mlir::Location loc, mlir::OperationState &) {
794 mlir::Block *switchBlock = builder.getBlock();
796 auto emitMemOrderCase = [&](llvm::ArrayRef<cir::MemOrder> caseOrders) {
798 for (int i = 1, e = caseOrders.size(); i < e; i++)
799 assert((getEffectiveAtomicMemOrder(caseOrders[i - 1], isStore,
801 getEffectiveAtomicMemOrder(caseOrders[i], isStore, isLoad,
803 "Effective memory order must be same!");
805 if (caseOrders.empty()) {
806 emitMemOrderDefaultCaseLabel(builder, loc);
810 emitAtomicOpFn(cir::MemOrder::Relaxed);
811 } else if (std::optional<cir::MemOrder> actualOrder =
812 getEffectiveAtomicMemOrder(caseOrders[0], isStore,
815 if (!isFence && actualOrder == cir::MemOrder::Relaxed)
820 emitMemOrderCaseLabel(builder, loc, order.getType(), caseOrders);
821 emitAtomicOpFn(actualOrder.value());
826 builder.createBreak(loc);
827 builder.setInsertionPointToEnd(switchBlock);
830 emitMemOrderCase( {});
831 emitMemOrderCase({cir::MemOrder::Relaxed});
832 emitMemOrderCase({cir::MemOrder::Consume, cir::MemOrder::Acquire});
833 emitMemOrderCase({cir::MemOrder::Release});
834 emitMemOrderCase({cir::MemOrder::AcquireRelease});
835 emitMemOrderCase({cir::MemOrder::SequentiallyConsistent});
842 const Expr *memOrder,
bool isStore,
bool isLoad,
bool isFence,
843 llvm::function_ref<
void(cir::MemOrder)> emitAtomicOpFn) {
847 uint64_t constOrder = eval.
Val.
getInt().getZExtValue();
852 cir::MemOrder oriOrder =
static_cast<cir::MemOrder
>(constOrder);
853 if (std::optional<cir::MemOrder> actualOrder =
855 emitAtomicOpFn(actualOrder.value());
870 memTy = ty->getValueType();
872 Expr *isWeakExpr =
nullptr;
873 Expr *orderFailExpr =
nullptr;
881 if (e->
getOp() == AtomicExpr::AO__c11_atomic_init) {
893 std::optional<Expr::EvalResult> scopeConst;
896 scopeConst.emplace(std::move(eval));
898 switch (e->
getOp()) {
903 case AtomicExpr::AO__c11_atomic_init:
904 llvm_unreachable(
"already handled above with emitAtomicInit");
906 case AtomicExpr::AO__atomic_load_n:
907 case AtomicExpr::AO__scoped_atomic_load_n:
908 case AtomicExpr::AO__c11_atomic_load:
909 case AtomicExpr::AO__atomic_test_and_set:
910 case AtomicExpr::AO__atomic_clear:
913 case AtomicExpr::AO__atomic_load:
914 case AtomicExpr::AO__scoped_atomic_load:
918 case AtomicExpr::AO__atomic_store:
919 case AtomicExpr::AO__scoped_atomic_store:
923 case AtomicExpr::AO__atomic_exchange:
924 case AtomicExpr::AO__scoped_atomic_exchange:
929 case AtomicExpr::AO__atomic_compare_exchange:
930 case AtomicExpr::AO__atomic_compare_exchange_n:
931 case AtomicExpr::AO__c11_atomic_compare_exchange_weak:
932 case AtomicExpr::AO__c11_atomic_compare_exchange_strong:
933 case AtomicExpr::AO__scoped_atomic_compare_exchange:
934 case AtomicExpr::AO__scoped_atomic_compare_exchange_n:
936 if (e->
getOp() == AtomicExpr::AO__atomic_compare_exchange ||
937 e->
getOp() == AtomicExpr::AO__scoped_atomic_compare_exchange)
942 if (e->
getOp() == AtomicExpr::AO__atomic_compare_exchange_n ||
943 e->
getOp() == AtomicExpr::AO__atomic_compare_exchange ||
944 e->
getOp() == AtomicExpr::AO__scoped_atomic_compare_exchange_n ||
945 e->
getOp() == AtomicExpr::AO__scoped_atomic_compare_exchange)
949 case AtomicExpr::AO__c11_atomic_fetch_add:
950 case AtomicExpr::AO__c11_atomic_fetch_sub:
953 "atomic fetch-and-add and fetch-and-sub for pointers");
957 case AtomicExpr::AO__atomic_fetch_add:
958 case AtomicExpr::AO__atomic_fetch_max:
959 case AtomicExpr::AO__atomic_fetch_min:
960 case AtomicExpr::AO__atomic_fetch_sub:
961 case AtomicExpr::AO__atomic_add_fetch:
962 case AtomicExpr::AO__atomic_max_fetch:
963 case AtomicExpr::AO__atomic_min_fetch:
964 case AtomicExpr::AO__atomic_sub_fetch:
965 case AtomicExpr::AO__c11_atomic_fetch_max:
966 case AtomicExpr::AO__c11_atomic_fetch_min:
967 case AtomicExpr::AO__scoped_atomic_fetch_add:
968 case AtomicExpr::AO__scoped_atomic_fetch_max:
969 case AtomicExpr::AO__scoped_atomic_fetch_min:
970 case AtomicExpr::AO__scoped_atomic_fetch_sub:
971 case AtomicExpr::AO__scoped_atomic_add_fetch:
972 case AtomicExpr::AO__scoped_atomic_max_fetch:
973 case AtomicExpr::AO__scoped_atomic_min_fetch:
974 case AtomicExpr::AO__scoped_atomic_sub_fetch:
977 case AtomicExpr::AO__atomic_fetch_and:
978 case AtomicExpr::AO__atomic_fetch_nand:
979 case AtomicExpr::AO__atomic_fetch_or:
980 case AtomicExpr::AO__atomic_fetch_xor:
981 case AtomicExpr::AO__atomic_and_fetch:
982 case AtomicExpr::AO__atomic_nand_fetch:
983 case AtomicExpr::AO__atomic_or_fetch:
984 case AtomicExpr::AO__atomic_xor_fetch:
985 case AtomicExpr::AO__atomic_exchange_n:
986 case AtomicExpr::AO__atomic_store_n:
987 case AtomicExpr::AO__c11_atomic_fetch_and:
988 case AtomicExpr::AO__c11_atomic_fetch_nand:
989 case AtomicExpr::AO__c11_atomic_fetch_or:
990 case AtomicExpr::AO__c11_atomic_fetch_xor:
991 case AtomicExpr::AO__c11_atomic_exchange:
992 case AtomicExpr::AO__c11_atomic_store:
993 case AtomicExpr::AO__scoped_atomic_fetch_and:
994 case AtomicExpr::AO__scoped_atomic_fetch_nand:
995 case AtomicExpr::AO__scoped_atomic_fetch_or:
996 case AtomicExpr::AO__scoped_atomic_fetch_xor:
997 case AtomicExpr::AO__scoped_atomic_and_fetch:
998 case AtomicExpr::AO__scoped_atomic_nand_fetch:
999 case AtomicExpr::AO__scoped_atomic_or_fetch:
1000 case AtomicExpr::AO__scoped_atomic_xor_fetch:
1001 case AtomicExpr::AO__scoped_atomic_store_n:
1002 case AtomicExpr::AO__scoped_atomic_exchange_n:
1009 bool shouldCastToIntPtrTy =
1018 if (shouldCastToIntPtrTy) {
1019 ptr = atomics.castToAtomicIntPointer(ptr);
1021 val1 = atomics.convertToAtomicIntPointer(val1);
1024 if (shouldCastToIntPtrTy)
1025 dest = atomics.castToAtomicIntPointer(dest);
1028 }
else if (e->
getOp() == AtomicExpr::AO__atomic_test_and_set) {
1030 "test_and_set.bool");
1032 dest = atomics.createTempAlloca();
1033 if (shouldCastToIntPtrTy)
1034 dest = atomics.castToAtomicIntPointer(dest);
1037 bool powerOf2Size = (size & (size - 1)) == 0;
1038 bool useLibCall = !powerOf2Size || (size > 16);
1055 bool isStore = e->
getOp() == AtomicExpr::AO__c11_atomic_store ||
1056 e->
getOp() == AtomicExpr::AO__opencl_atomic_store ||
1057 e->
getOp() == AtomicExpr::AO__hip_atomic_store ||
1058 e->
getOp() == AtomicExpr::AO__atomic_store ||
1059 e->
getOp() == AtomicExpr::AO__atomic_store_n ||
1060 e->
getOp() == AtomicExpr::AO__scoped_atomic_store ||
1061 e->
getOp() == AtomicExpr::AO__scoped_atomic_store_n ||
1062 e->
getOp() == AtomicExpr::AO__atomic_clear;
1063 bool isLoad = e->
getOp() == AtomicExpr::AO__c11_atomic_load ||
1064 e->
getOp() == AtomicExpr::AO__opencl_atomic_load ||
1065 e->
getOp() == AtomicExpr::AO__hip_atomic_load ||
1066 e->
getOp() == AtomicExpr::AO__atomic_load ||
1067 e->
getOp() == AtomicExpr::AO__atomic_load_n ||
1068 e->
getOp() == AtomicExpr::AO__scoped_atomic_load ||
1069 e->
getOp() == AtomicExpr::AO__scoped_atomic_load_n;
1071 auto emitAtomicOpCallBackFn = [&](cir::MemOrder memOrder) {
1072 emitAtomicOp(*
this, e, dest, ptr, val1, val2, isWeakExpr, orderFailExpr,
1073 size, memOrder, scopeConst, scope);
1076 emitAtomicOpCallBackFn);
1088 auto order = cir::MemOrder::SequentiallyConsistent;
1101 cir::MemOrder order,
bool isVolatile,
1105 mlir::Location loc = dest.
getPointer().getLoc();
1110 AtomicInfo atomics(*
this, dest, loc);
1111 LValue lvalue = atomics.getAtomicLValue();
1116 atomics.emitCopyIntoMemory(rvalue);
1121 if (atomics.shouldUseLibCall()) {
1123 cgm.errorNYI(loc,
"emitAtomicStore: atomic store with library call");
1128 mlir::Value valueToStore = atomics.convertRValueToInt(rvalue);
1131 Address addr = atomics.getAtomicAddress();
1132 if (mlir::Value value = atomics.getScalarRValValueOrNull(rvalue)) {
1134 addr = atomics.castToAtomicIntPointer(addr);
1139 cir::StoreOp store = builder.createStore(loc, valueToStore, addr);
1144 store.setMemOrder(order);
1149 store.setIsVolatile(
true);
1155 cgm.errorNYI(loc,
"emitAtomicStore: non-simple atomic lvalue");
1162 switch (atomics.getEvaluationKind()) {
1178 bool zeroed =
false;
1180 zeroed = atomics.emitMemSetZeroIfNecessary();
1181 dest = atomics.projectValue();
1196 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 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 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 emitMemOrderDefaultCaseLabel(CIRGenBuilderTy &builder, mlir::Location loc)
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)
cir::BreakOp createBreak(mlir::Location loc)
Create a break operation.
mlir::Value createNot(mlir::Value value)
mlir::Value createPtrBitcast(mlir::Value src, mlir::Type newPointeeTy)
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)
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 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
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)
mlir::Value getValue() const
Return the value of this scalar value.
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.
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.
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.