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__atomic_fetch_uinc:
641 case AtomicExpr::AO__scoped_atomic_fetch_uinc:
642 opName = cir::AtomicFetchOp::getOperationName();
643 fetchAttr = cir::AtomicFetchKindAttr::get(builder.getContext(),
644 cir::AtomicFetchKind::UIncWrap);
647 case AtomicExpr::AO__atomic_fetch_udec:
648 case AtomicExpr::AO__scoped_atomic_fetch_udec:
649 opName = cir::AtomicFetchOp::getOperationName();
650 fetchAttr = cir::AtomicFetchKindAttr::get(builder.getContext(),
651 cir::AtomicFetchKind::UDecWrap);
654 case AtomicExpr::AO__opencl_atomic_init:
656 case AtomicExpr::AO__hip_atomic_compare_exchange_strong:
657 case AtomicExpr::AO__opencl_atomic_compare_exchange_strong:
659 case AtomicExpr::AO__opencl_atomic_compare_exchange_weak:
660 case AtomicExpr::AO__hip_atomic_compare_exchange_weak:
662 case AtomicExpr::AO__opencl_atomic_load:
663 case AtomicExpr::AO__hip_atomic_load:
665 case AtomicExpr::AO__opencl_atomic_store:
666 case AtomicExpr::AO__hip_atomic_store:
668 case AtomicExpr::AO__hip_atomic_exchange:
669 case AtomicExpr::AO__opencl_atomic_exchange:
671 case AtomicExpr::AO__hip_atomic_fetch_add:
672 case AtomicExpr::AO__opencl_atomic_fetch_add:
674 case AtomicExpr::AO__hip_atomic_fetch_sub:
675 case AtomicExpr::AO__opencl_atomic_fetch_sub:
677 case AtomicExpr::AO__hip_atomic_fetch_min:
678 case AtomicExpr::AO__opencl_atomic_fetch_min:
680 case AtomicExpr::AO__hip_atomic_fetch_max:
681 case AtomicExpr::AO__opencl_atomic_fetch_max:
683 case AtomicExpr::AO__hip_atomic_fetch_and:
684 case AtomicExpr::AO__opencl_atomic_fetch_and:
686 case AtomicExpr::AO__hip_atomic_fetch_or:
687 case AtomicExpr::AO__opencl_atomic_fetch_or:
689 case AtomicExpr::AO__hip_atomic_fetch_xor:
690 case AtomicExpr::AO__opencl_atomic_fetch_xor:
695 assert(!opName.empty() &&
"expected operation name to build");
696 mlir::Value loadVal1 = builder.
createLoad(loc, val1);
700 mlir::Operation *rmwOp = builder.create(loc, builder.getStringAttr(opName),
701 atomicOperands, atomicResTys);
704 rmwOp->setAttr(
"binop", fetchAttr);
705 rmwOp->setAttr(
"mem_order", orderAttr);
706 rmwOp->setAttr(
"sync_scope", scopeAttr);
707 if (
expr->isVolatile())
708 rmwOp->setAttr(
"is_volatile", builder.getUnitAttr());
709 if (fetchFirst && opName == cir::AtomicFetchOp::getOperationName())
710 rmwOp->setAttr(
"fetch_first", builder.getUnitAttr());
712 mlir::Value result = rmwOp->getResult(0);
723 cgf.
cgm.
errorNYI(range,
"convertSyncScopeToCIR: unhandled sync scope");
724 return cir::SyncScopeKind::System;
728 return cir::SyncScopeKind::SingleThread;
730 return cir::SyncScopeKind::System;
736 Expr *isWeakExpr,
Expr *failureOrderExpr, int64_t size,
738 const std::optional<Expr::EvalResult> &scopeConst,
739 mlir::Value scopeValue) {
740 std::unique_ptr<AtomicScopeModel> scopeModel =
expr->getScopeModel();
743 emitAtomicOp(cgf,
expr, dest, ptr, val1, val2, isWeakExpr, failureOrderExpr,
744 size, order, cir::SyncScopeKind::System);
748 if (scopeConst.has_value()) {
750 cgf,
expr->getScope()->getSourceRange(),
751 scopeModel->map(scopeConst->Val.getInt().getZExtValue()));
752 emitAtomicOp(cgf,
expr, dest, ptr, val1, val2, isWeakExpr, failureOrderExpr,
753 size, order, mappedScope);
758 cgf.
cgm.
errorNYI(
expr->getSourceRange(),
"emitAtomicOp: dynamic sync scope");
761static std::optional<cir::MemOrder>
771 if (oriOrder == cir::MemOrder::Consume ||
772 oriOrder == cir::MemOrder::Acquire ||
773 oriOrder == cir::MemOrder::AcquireRelease)
776 if (oriOrder == cir::MemOrder::Release ||
777 oriOrder == cir::MemOrder::AcquireRelease)
779 }
else if (isFence) {
780 if (oriOrder == cir::MemOrder::Relaxed)
785 if (oriOrder == cir::MemOrder::Consume)
786 return cir::MemOrder::Acquire;
791 CIRGenFunction &cgf, mlir::Value order,
bool isStore,
bool isLoad,
792 bool isFence, llvm::function_ref<
void(cir::MemOrder)> emitAtomicOpFn) {
800 cir::SwitchOp::create(
801 builder, order.getLoc(), order,
802 [&](mlir::OpBuilder &, mlir::Location loc, mlir::OperationState &) {
803 mlir::Block *switchBlock = builder.getBlock();
805 auto emitMemOrderCase = [&](llvm::ArrayRef<cir::MemOrder> caseOrders) {
807 for (int i = 1, e = caseOrders.size(); i < e; i++)
808 assert((getEffectiveAtomicMemOrder(caseOrders[i - 1], isStore,
810 getEffectiveAtomicMemOrder(caseOrders[i], isStore, isLoad,
812 "Effective memory order must be same!");
814 if (caseOrders.empty()) {
815 emitMemOrderDefaultCaseLabel(builder, loc);
819 emitAtomicOpFn(cir::MemOrder::Relaxed);
820 } else if (std::optional<cir::MemOrder> actualOrder =
821 getEffectiveAtomicMemOrder(caseOrders[0], isStore,
824 if (!isFence && actualOrder == cir::MemOrder::Relaxed)
829 emitMemOrderCaseLabel(builder, loc, order.getType(), caseOrders);
830 emitAtomicOpFn(actualOrder.value());
835 builder.createBreak(loc);
836 builder.setInsertionPointToEnd(switchBlock);
839 emitMemOrderCase( {});
840 emitMemOrderCase({cir::MemOrder::Relaxed});
841 emitMemOrderCase({cir::MemOrder::Consume, cir::MemOrder::Acquire});
842 emitMemOrderCase({cir::MemOrder::Release});
843 emitMemOrderCase({cir::MemOrder::AcquireRelease});
844 emitMemOrderCase({cir::MemOrder::SequentiallyConsistent});
851 const Expr *memOrder,
bool isStore,
bool isLoad,
bool isFence,
852 llvm::function_ref<
void(cir::MemOrder)> emitAtomicOpFn) {
856 uint64_t constOrder = eval.
Val.
getInt().getZExtValue();
861 cir::MemOrder oriOrder =
static_cast<cir::MemOrder
>(constOrder);
862 if (std::optional<cir::MemOrder> actualOrder =
864 emitAtomicOpFn(actualOrder.value());
879 memTy = ty->getValueType();
881 Expr *isWeakExpr =
nullptr;
882 Expr *orderFailExpr =
nullptr;
890 if (e->
getOp() == AtomicExpr::AO__c11_atomic_init) {
902 std::optional<Expr::EvalResult> scopeConst;
905 scopeConst.emplace(std::move(eval));
907 switch (e->
getOp()) {
912 case AtomicExpr::AO__c11_atomic_init:
913 llvm_unreachable(
"already handled above with emitAtomicInit");
915 case AtomicExpr::AO__atomic_load_n:
916 case AtomicExpr::AO__scoped_atomic_load_n:
917 case AtomicExpr::AO__c11_atomic_load:
918 case AtomicExpr::AO__atomic_test_and_set:
919 case AtomicExpr::AO__atomic_clear:
922 case AtomicExpr::AO__atomic_load:
923 case AtomicExpr::AO__scoped_atomic_load:
927 case AtomicExpr::AO__atomic_store:
928 case AtomicExpr::AO__scoped_atomic_store:
932 case AtomicExpr::AO__atomic_exchange:
933 case AtomicExpr::AO__scoped_atomic_exchange:
938 case AtomicExpr::AO__atomic_compare_exchange:
939 case AtomicExpr::AO__atomic_compare_exchange_n:
940 case AtomicExpr::AO__c11_atomic_compare_exchange_weak:
941 case AtomicExpr::AO__c11_atomic_compare_exchange_strong:
942 case AtomicExpr::AO__scoped_atomic_compare_exchange:
943 case AtomicExpr::AO__scoped_atomic_compare_exchange_n:
945 if (e->
getOp() == AtomicExpr::AO__atomic_compare_exchange ||
946 e->
getOp() == AtomicExpr::AO__scoped_atomic_compare_exchange)
951 if (e->
getOp() == AtomicExpr::AO__atomic_compare_exchange_n ||
952 e->
getOp() == AtomicExpr::AO__atomic_compare_exchange ||
953 e->
getOp() == AtomicExpr::AO__scoped_atomic_compare_exchange_n ||
954 e->
getOp() == AtomicExpr::AO__scoped_atomic_compare_exchange)
958 case AtomicExpr::AO__c11_atomic_fetch_add:
959 case AtomicExpr::AO__c11_atomic_fetch_sub:
962 "atomic fetch-and-add and fetch-and-sub for pointers");
966 case AtomicExpr::AO__atomic_fetch_add:
967 case AtomicExpr::AO__atomic_fetch_max:
968 case AtomicExpr::AO__atomic_fetch_min:
969 case AtomicExpr::AO__atomic_fetch_sub:
970 case AtomicExpr::AO__atomic_add_fetch:
971 case AtomicExpr::AO__atomic_max_fetch:
972 case AtomicExpr::AO__atomic_min_fetch:
973 case AtomicExpr::AO__atomic_sub_fetch:
974 case AtomicExpr::AO__c11_atomic_fetch_max:
975 case AtomicExpr::AO__c11_atomic_fetch_min:
976 case AtomicExpr::AO__scoped_atomic_fetch_add:
977 case AtomicExpr::AO__scoped_atomic_fetch_max:
978 case AtomicExpr::AO__scoped_atomic_fetch_min:
979 case AtomicExpr::AO__scoped_atomic_fetch_sub:
980 case AtomicExpr::AO__scoped_atomic_add_fetch:
981 case AtomicExpr::AO__scoped_atomic_max_fetch:
982 case AtomicExpr::AO__scoped_atomic_min_fetch:
983 case AtomicExpr::AO__scoped_atomic_sub_fetch:
986 case AtomicExpr::AO__atomic_fetch_and:
987 case AtomicExpr::AO__atomic_fetch_nand:
988 case AtomicExpr::AO__atomic_fetch_or:
989 case AtomicExpr::AO__atomic_fetch_xor:
990 case AtomicExpr::AO__atomic_and_fetch:
991 case AtomicExpr::AO__atomic_nand_fetch:
992 case AtomicExpr::AO__atomic_or_fetch:
993 case AtomicExpr::AO__atomic_xor_fetch:
994 case AtomicExpr::AO__atomic_exchange_n:
995 case AtomicExpr::AO__atomic_store_n:
996 case AtomicExpr::AO__c11_atomic_fetch_and:
997 case AtomicExpr::AO__c11_atomic_fetch_nand:
998 case AtomicExpr::AO__c11_atomic_fetch_or:
999 case AtomicExpr::AO__c11_atomic_fetch_xor:
1000 case AtomicExpr::AO__c11_atomic_exchange:
1001 case AtomicExpr::AO__c11_atomic_store:
1002 case AtomicExpr::AO__scoped_atomic_fetch_and:
1003 case AtomicExpr::AO__scoped_atomic_fetch_nand:
1004 case AtomicExpr::AO__scoped_atomic_fetch_or:
1005 case AtomicExpr::AO__scoped_atomic_fetch_xor:
1006 case AtomicExpr::AO__scoped_atomic_and_fetch:
1007 case AtomicExpr::AO__scoped_atomic_nand_fetch:
1008 case AtomicExpr::AO__scoped_atomic_or_fetch:
1009 case AtomicExpr::AO__scoped_atomic_xor_fetch:
1010 case AtomicExpr::AO__scoped_atomic_store_n:
1011 case AtomicExpr::AO__scoped_atomic_exchange_n:
1012 case AtomicExpr::AO__atomic_fetch_uinc:
1013 case AtomicExpr::AO__atomic_fetch_udec:
1020 bool shouldCastToIntPtrTy =
1029 if (shouldCastToIntPtrTy) {
1030 ptr = atomics.castToAtomicIntPointer(ptr);
1032 val1 = atomics.convertToAtomicIntPointer(val1);
1035 if (shouldCastToIntPtrTy)
1036 dest = atomics.castToAtomicIntPointer(dest);
1039 }
else if (e->
getOp() == AtomicExpr::AO__atomic_test_and_set) {
1041 "test_and_set.bool");
1043 dest = atomics.createTempAlloca();
1044 if (shouldCastToIntPtrTy)
1045 dest = atomics.castToAtomicIntPointer(dest);
1048 bool powerOf2Size = (size & (size - 1)) == 0;
1049 bool useLibCall = !powerOf2Size || (size > 16);
1066 bool isStore = e->
getOp() == AtomicExpr::AO__c11_atomic_store ||
1067 e->
getOp() == AtomicExpr::AO__opencl_atomic_store ||
1068 e->
getOp() == AtomicExpr::AO__hip_atomic_store ||
1069 e->
getOp() == AtomicExpr::AO__atomic_store ||
1070 e->
getOp() == AtomicExpr::AO__atomic_store_n ||
1071 e->
getOp() == AtomicExpr::AO__scoped_atomic_store ||
1072 e->
getOp() == AtomicExpr::AO__scoped_atomic_store_n ||
1073 e->
getOp() == AtomicExpr::AO__atomic_clear;
1074 bool isLoad = e->
getOp() == AtomicExpr::AO__c11_atomic_load ||
1075 e->
getOp() == AtomicExpr::AO__opencl_atomic_load ||
1076 e->
getOp() == AtomicExpr::AO__hip_atomic_load ||
1077 e->
getOp() == AtomicExpr::AO__atomic_load ||
1078 e->
getOp() == AtomicExpr::AO__atomic_load_n ||
1079 e->
getOp() == AtomicExpr::AO__scoped_atomic_load ||
1080 e->
getOp() == AtomicExpr::AO__scoped_atomic_load_n;
1082 auto emitAtomicOpCallBackFn = [&](cir::MemOrder memOrder) {
1083 emitAtomicOp(*
this, e, dest, ptr, val1, val2, isWeakExpr, orderFailExpr,
1084 size, memOrder, scopeConst, scope);
1087 emitAtomicOpCallBackFn);
1099 auto order = cir::MemOrder::SequentiallyConsistent;
1112 cir::MemOrder order,
bool isVolatile,
1116 mlir::Location loc = dest.
getPointer().getLoc();
1121 AtomicInfo atomics(*
this, dest, loc);
1122 LValue lvalue = atomics.getAtomicLValue();
1127 atomics.emitCopyIntoMemory(rvalue);
1132 if (atomics.shouldUseLibCall()) {
1134 cgm.errorNYI(loc,
"emitAtomicStore: atomic store with library call");
1139 mlir::Value valueToStore = atomics.convertRValueToInt(rvalue);
1142 Address addr = atomics.getAtomicAddress();
1143 if (mlir::Value value = atomics.getScalarRValValueOrNull(rvalue)) {
1145 addr = atomics.castToAtomicIntPointer(addr);
1150 cir::StoreOp store = builder.createStore(loc, valueToStore, addr);
1155 store.setMemOrder(order);
1160 store.setIsVolatile(
true);
1166 cgm.errorNYI(loc,
"emitAtomicStore: non-simple atomic lvalue");
1173 switch (atomics.getEvaluationKind()) {
1189 bool zeroed =
false;
1191 zeroed = atomics.emitMemSetZeroIfNecessary();
1192 dest = atomics.projectValue();
1207 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 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)
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.