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::ArrayAttr valuesAttr = builder.getArrayAttr({});
291 mlir::OpBuilder::InsertPoint insertPoint;
292 cir::CaseOp::create(builder, loc, valuesAttr, cir::CaseOpKind::Default,
294 builder.restoreInsertionPoint(insertPoint);
300 mlir::Type orderType,
303 for (cir::MemOrder order : orders)
304 orderAttrs.push_back(cir::IntAttr::get(orderType,
static_cast<int>(order)));
305 mlir::ArrayAttr ordersAttr = builder.getArrayAttr(orderAttrs);
307 mlir::OpBuilder::InsertPoint insertPoint;
308 cir::CaseOp::create(builder, loc, ordersAttr, cir::CaseOpKind::Anyof,
310 builder.restoreInsertionPoint(insertPoint);
316 cir::MemOrder successOrder,
317 cir::MemOrder failureOrder,
318 cir::SyncScopeKind scope) {
322 mlir::Value expected = builder.
createLoad(loc, val1);
323 mlir::Value desired = builder.
createLoad(loc, val2);
325 auto cmpxchg = cir::AtomicCmpXchgOp::create(
334 cmpxchg.setWeak(isWeak);
336 mlir::Value failed = builder.
createNot(cmpxchg.getSuccess());
337 cir::IfOp::create(builder, loc, failed,
false,
338 [&](mlir::OpBuilder &, mlir::Location) {
339 auto ptrTy = mlir::cast<cir::PointerType>(
358 Expr *failureOrderExpr, uint64_t size,
359 cir::MemOrder successOrder,
360 cir::SyncScopeKind scope) {
363 uint64_t failureOrderInt = failureOrderEval.
Val.
getInt().getZExtValue();
365 cir::MemOrder failureOrder;
367 failureOrder = cir::MemOrder::Relaxed;
369 switch ((cir::MemOrder)failureOrderInt) {
370 case cir::MemOrder::Relaxed:
373 case cir::MemOrder::Release:
374 case cir::MemOrder::AcquireRelease:
375 failureOrder = cir::MemOrder::Relaxed;
377 case cir::MemOrder::Consume:
378 case cir::MemOrder::Acquire:
379 failureOrder = cir::MemOrder::Acquire;
381 case cir::MemOrder::SequentiallyConsistent:
382 failureOrder = cir::MemOrder::SequentiallyConsistent;
392 failureOrder, scope);
400 mlir::Value failureOrderVal = cgf.
emitScalarExpr(failureOrderExpr);
402 cir::SwitchOp::create(
404 [&](mlir::OpBuilder &
b, mlir::Location loc, mlir::OperationState &os) {
405 mlir::Block *switchBlock = cgf.getBuilder().getBlock();
417 emitDefaultCaseLabel(cgf.getBuilder(), atomicLoc);
418 emitAtomicCmpXchg(cgf, e, isWeak, dest, ptr, val1, val2, size,
419 successOrder, cir::MemOrder::Relaxed, scope);
420 cgf.getBuilder().createBreak(atomicLoc);
421 cgf.getBuilder().setInsertionPointToEnd(switchBlock);
425 emitMemOrderCaseLabel(cgf.getBuilder(), loc, failureOrderVal.getType(),
426 {cir::MemOrder::Consume, cir::MemOrder::Acquire});
428 successOrder, cir::MemOrder::Acquire, scope);
430 cgf.
getBuilder().setInsertionPointToEnd(switchBlock);
434 {cir::MemOrder::SequentiallyConsistent});
436 successOrder, cir::MemOrder::SequentiallyConsistent,
439 cgf.
getBuilder().setInsertionPointToEnd(switchBlock);
447 Expr *isWeakExpr,
Expr *failureOrderExpr, int64_t size,
448 cir::MemOrder order, cir::SyncScopeKind scope) {
450 llvm::StringRef opName;
453 mlir::Location loc = cgf.
getLoc(
expr->getSourceRange());
454 auto orderAttr = cir::MemOrderAttr::get(builder.getContext(), order);
455 auto scopeAttr = cir::SyncScopeKindAttr::get(builder.getContext(), scope);
456 cir::AtomicFetchKindAttr fetchAttr;
457 bool fetchFirst =
true;
459 switch (
expr->getOp()) {
460 case AtomicExpr::AO__c11_atomic_init:
461 llvm_unreachable(
"already handled!");
463 case AtomicExpr::AO__c11_atomic_compare_exchange_strong:
465 val2, failureOrderExpr, size, order, scope);
468 case AtomicExpr::AO__c11_atomic_compare_exchange_weak:
470 val2, failureOrderExpr, size, order, scope);
473 case AtomicExpr::AO__atomic_compare_exchange:
474 case AtomicExpr::AO__atomic_compare_exchange_n:
475 case AtomicExpr::AO__scoped_atomic_compare_exchange:
476 case AtomicExpr::AO__scoped_atomic_compare_exchange_n: {
480 failureOrderExpr, size, order, scope);
484 "emitAtomicOp: non-constant isWeak");
489 case AtomicExpr::AO__c11_atomic_load:
490 case AtomicExpr::AO__atomic_load_n:
491 case AtomicExpr::AO__atomic_load:
492 case AtomicExpr::AO__scoped_atomic_load_n:
493 case AtomicExpr::AO__scoped_atomic_load: {
497 load->setAttr(
"mem_order", orderAttr);
498 load->setAttr(
"sync_scope", scopeAttr);
500 builder.
createStore(loc, load->getResult(0), dest);
504 case AtomicExpr::AO__c11_atomic_store:
505 case AtomicExpr::AO__atomic_store_n:
506 case AtomicExpr::AO__atomic_store:
507 case AtomicExpr::AO__scoped_atomic_store:
508 case AtomicExpr::AO__scoped_atomic_store_n: {
509 cir::LoadOp loadVal1 = builder.
createLoad(loc, val1);
514 mlir::IntegerAttr{}, scopeAttr, orderAttr);
518 case AtomicExpr::AO__c11_atomic_exchange:
519 case AtomicExpr::AO__atomic_exchange_n:
520 case AtomicExpr::AO__atomic_exchange:
521 case AtomicExpr::AO__scoped_atomic_exchange_n:
522 case AtomicExpr::AO__scoped_atomic_exchange:
523 opName = cir::AtomicXchgOp::getOperationName();
526 case AtomicExpr::AO__atomic_add_fetch:
527 case AtomicExpr::AO__scoped_atomic_add_fetch:
530 case AtomicExpr::AO__c11_atomic_fetch_add:
531 case AtomicExpr::AO__atomic_fetch_add:
532 case AtomicExpr::AO__scoped_atomic_fetch_add:
533 opName = cir::AtomicFetchOp::getOperationName();
534 fetchAttr = cir::AtomicFetchKindAttr::get(builder.getContext(),
535 cir::AtomicFetchKind::Add);
538 case AtomicExpr::AO__atomic_sub_fetch:
539 case AtomicExpr::AO__scoped_atomic_sub_fetch:
542 case AtomicExpr::AO__c11_atomic_fetch_sub:
543 case AtomicExpr::AO__atomic_fetch_sub:
544 case AtomicExpr::AO__scoped_atomic_fetch_sub:
545 opName = cir::AtomicFetchOp::getOperationName();
546 fetchAttr = cir::AtomicFetchKindAttr::get(builder.getContext(),
547 cir::AtomicFetchKind::Sub);
550 case AtomicExpr::AO__atomic_min_fetch:
551 case AtomicExpr::AO__scoped_atomic_min_fetch:
554 case AtomicExpr::AO__c11_atomic_fetch_min:
555 case AtomicExpr::AO__atomic_fetch_min:
556 case AtomicExpr::AO__scoped_atomic_fetch_min:
557 opName = cir::AtomicFetchOp::getOperationName();
558 fetchAttr = cir::AtomicFetchKindAttr::get(builder.getContext(),
559 cir::AtomicFetchKind::Min);
562 case AtomicExpr::AO__atomic_max_fetch:
563 case AtomicExpr::AO__scoped_atomic_max_fetch:
566 case AtomicExpr::AO__c11_atomic_fetch_max:
567 case AtomicExpr::AO__atomic_fetch_max:
568 case AtomicExpr::AO__scoped_atomic_fetch_max:
569 opName = cir::AtomicFetchOp::getOperationName();
570 fetchAttr = cir::AtomicFetchKindAttr::get(builder.getContext(),
571 cir::AtomicFetchKind::Max);
574 case AtomicExpr::AO__atomic_and_fetch:
575 case AtomicExpr::AO__scoped_atomic_and_fetch:
578 case AtomicExpr::AO__c11_atomic_fetch_and:
579 case AtomicExpr::AO__atomic_fetch_and:
580 case AtomicExpr::AO__scoped_atomic_fetch_and:
581 opName = cir::AtomicFetchOp::getOperationName();
582 fetchAttr = cir::AtomicFetchKindAttr::get(builder.getContext(),
583 cir::AtomicFetchKind::And);
586 case AtomicExpr::AO__atomic_or_fetch:
587 case AtomicExpr::AO__scoped_atomic_or_fetch:
590 case AtomicExpr::AO__c11_atomic_fetch_or:
591 case AtomicExpr::AO__atomic_fetch_or:
592 case AtomicExpr::AO__scoped_atomic_fetch_or:
593 opName = cir::AtomicFetchOp::getOperationName();
594 fetchAttr = cir::AtomicFetchKindAttr::get(builder.getContext(),
595 cir::AtomicFetchKind::Or);
598 case AtomicExpr::AO__atomic_xor_fetch:
599 case AtomicExpr::AO__scoped_atomic_xor_fetch:
602 case AtomicExpr::AO__c11_atomic_fetch_xor:
603 case AtomicExpr::AO__atomic_fetch_xor:
604 case AtomicExpr::AO__scoped_atomic_fetch_xor:
605 opName = cir::AtomicFetchOp::getOperationName();
606 fetchAttr = cir::AtomicFetchKindAttr::get(builder.getContext(),
607 cir::AtomicFetchKind::Xor);
610 case AtomicExpr::AO__atomic_nand_fetch:
611 case AtomicExpr::AO__scoped_atomic_nand_fetch:
614 case AtomicExpr::AO__c11_atomic_fetch_nand:
615 case AtomicExpr::AO__atomic_fetch_nand:
616 case AtomicExpr::AO__scoped_atomic_fetch_nand:
617 opName = cir::AtomicFetchOp::getOperationName();
618 fetchAttr = cir::AtomicFetchKindAttr::get(builder.getContext(),
619 cir::AtomicFetchKind::Nand);
622 case AtomicExpr::AO__atomic_test_and_set: {
623 auto op = cir::AtomicTestAndSetOp::create(
631 case AtomicExpr::AO__atomic_clear: {
632 cir::AtomicClearOp::create(
639 case AtomicExpr::AO__atomic_fetch_uinc:
640 case AtomicExpr::AO__scoped_atomic_fetch_uinc:
641 opName = cir::AtomicFetchOp::getOperationName();
642 fetchAttr = cir::AtomicFetchKindAttr::get(builder.getContext(),
643 cir::AtomicFetchKind::UIncWrap);
646 case AtomicExpr::AO__atomic_fetch_udec:
647 case AtomicExpr::AO__scoped_atomic_fetch_udec:
648 opName = cir::AtomicFetchOp::getOperationName();
649 fetchAttr = cir::AtomicFetchKindAttr::get(builder.getContext(),
650 cir::AtomicFetchKind::UDecWrap);
653 case AtomicExpr::AO__opencl_atomic_init:
655 case AtomicExpr::AO__hip_atomic_compare_exchange_strong:
656 case AtomicExpr::AO__opencl_atomic_compare_exchange_strong:
658 case AtomicExpr::AO__opencl_atomic_compare_exchange_weak:
659 case AtomicExpr::AO__hip_atomic_compare_exchange_weak:
661 case AtomicExpr::AO__opencl_atomic_load:
662 case AtomicExpr::AO__hip_atomic_load:
664 case AtomicExpr::AO__opencl_atomic_store:
665 case AtomicExpr::AO__hip_atomic_store:
667 case AtomicExpr::AO__hip_atomic_exchange:
668 case AtomicExpr::AO__opencl_atomic_exchange:
670 case AtomicExpr::AO__hip_atomic_fetch_add:
671 case AtomicExpr::AO__opencl_atomic_fetch_add:
673 case AtomicExpr::AO__hip_atomic_fetch_sub:
674 case AtomicExpr::AO__opencl_atomic_fetch_sub:
676 case AtomicExpr::AO__hip_atomic_fetch_min:
677 case AtomicExpr::AO__opencl_atomic_fetch_min:
679 case AtomicExpr::AO__hip_atomic_fetch_max:
680 case AtomicExpr::AO__opencl_atomic_fetch_max:
682 case AtomicExpr::AO__hip_atomic_fetch_and:
683 case AtomicExpr::AO__opencl_atomic_fetch_and:
685 case AtomicExpr::AO__hip_atomic_fetch_or:
686 case AtomicExpr::AO__opencl_atomic_fetch_or:
688 case AtomicExpr::AO__hip_atomic_fetch_xor:
689 case AtomicExpr::AO__opencl_atomic_fetch_xor:
694 assert(!opName.empty() &&
"expected operation name to build");
695 mlir::Value loadVal1 = builder.
createLoad(loc, val1);
699 mlir::Operation *rmwOp = builder.create(loc, builder.getStringAttr(opName),
700 atomicOperands, atomicResTys);
703 rmwOp->setAttr(
"binop", fetchAttr);
704 rmwOp->setAttr(
"mem_order", orderAttr);
705 rmwOp->setAttr(
"sync_scope", scopeAttr);
706 if (
expr->isVolatile())
707 rmwOp->setAttr(
"is_volatile", builder.getUnitAttr());
708 if (fetchFirst && opName == cir::AtomicFetchOp::getOperationName())
709 rmwOp->setAttr(
"fetch_first", builder.getUnitAttr());
711 mlir::Value result = rmwOp->getResult(0);
721 return cir::SyncScopeKind::SingleThread;
723 return cir::SyncScopeKind::System;
725 return cir::SyncScopeKind::Device;
727 return cir::SyncScopeKind::Workgroup;
729 return cir::SyncScopeKind::Wavefront;
731 return cir::SyncScopeKind::Cluster;
734 return cir::SyncScopeKind::HIPSingleThread;
736 return cir::SyncScopeKind::HIPSystem;
738 return cir::SyncScopeKind::HIPAgent;
740 return cir::SyncScopeKind::HIPWorkgroup;
742 return cir::SyncScopeKind::HIPWavefront;
744 return cir::SyncScopeKind::HIPCluster;
747 return cir::SyncScopeKind::OpenCLWorkGroup;
749 return cir::SyncScopeKind::OpenCLDevice;
751 return cir::SyncScopeKind::OpenCLAllSVMDevices;
753 return cir::SyncScopeKind::OpenCLSubGroup;
756 llvm_unreachable(
"unhandled sync scope");
761 Expr *isWeakExpr,
Expr *failureOrderExpr, int64_t size,
763 const std::optional<Expr::EvalResult> &scopeConst,
764 mlir::Value scopeValue) {
765 std::unique_ptr<AtomicScopeModel> scopeModel =
expr->getScopeModel();
768 emitAtomicOp(cgf,
expr, dest, ptr, val1, val2, isWeakExpr, failureOrderExpr,
769 size, order, cir::SyncScopeKind::System);
773 if (scopeConst.has_value()) {
775 cgf,
expr->getScope()->getSourceRange(),
776 scopeModel->map(scopeConst->Val.getInt().getZExtValue()));
777 emitAtomicOp(cgf,
expr, dest, ptr, val1, val2, isWeakExpr, failureOrderExpr,
778 size, order, mappedScope);
785 mlir::Location loc = cgf.
getLoc(
expr->getSourceRange());
787 unsigned fallback = scopeModel->getFallBackValue();
789 cir::SwitchOp::create(
790 builder, loc, scopeValue,
791 [&](mlir::OpBuilder &, mlir::Location loc, mlir::OperationState &) {
792 mlir::Block *switchBlock = builder.getBlock();
796 cgf,
expr->getScope()->getSourceRange(), scopeModel->map(fallback));
799 failureOrderExpr, size, order, fallbackScope);
801 builder.setInsertionPointToEnd(switchBlock);
804 for (
unsigned scope : allScopes) {
805 if (scope == fallback)
809 cgf,
expr->getScope()->getSourceRange(), scopeModel->map(scope));
811 mlir::ArrayAttr casesAttr = builder.getArrayAttr(
812 {cir::IntAttr::get(scopeValue.getType(), scope)});
813 mlir::OpBuilder::InsertPoint insertPoint;
814 cir::CaseOp::create(builder, loc, casesAttr, cir::CaseOpKind::Equal,
817 builder.restoreInsertionPoint(insertPoint);
819 failureOrderExpr, size, order, cirScope);
821 builder.setInsertionPointToEnd(switchBlock);
828static std::optional<cir::MemOrder>
838 if (oriOrder == cir::MemOrder::Consume ||
839 oriOrder == cir::MemOrder::Acquire ||
840 oriOrder == cir::MemOrder::AcquireRelease)
843 if (oriOrder == cir::MemOrder::Release ||
844 oriOrder == cir::MemOrder::AcquireRelease)
846 }
else if (isFence) {
847 if (oriOrder == cir::MemOrder::Relaxed)
852 if (oriOrder == cir::MemOrder::Consume)
853 return cir::MemOrder::Acquire;
858 CIRGenFunction &cgf, mlir::Value order,
bool isStore,
bool isLoad,
859 bool isFence, llvm::function_ref<
void(cir::MemOrder)> emitAtomicOpFn) {
867 cir::SwitchOp::create(
868 builder, order.getLoc(), order,
869 [&](mlir::OpBuilder &, mlir::Location loc, mlir::OperationState &) {
870 mlir::Block *switchBlock = builder.getBlock();
872 auto emitMemOrderCase = [&](llvm::ArrayRef<cir::MemOrder> caseOrders) {
874 for (int i = 1, e = caseOrders.size(); i < e; i++)
875 assert((getEffectiveAtomicMemOrder(caseOrders[i - 1], isStore,
877 getEffectiveAtomicMemOrder(caseOrders[i], isStore, isLoad,
879 "Effective memory order must be same!");
881 if (caseOrders.empty()) {
882 emitDefaultCaseLabel(builder, loc);
886 emitAtomicOpFn(cir::MemOrder::Relaxed);
887 } else if (std::optional<cir::MemOrder> actualOrder =
888 getEffectiveAtomicMemOrder(caseOrders[0], isStore,
891 if (!isFence && actualOrder == cir::MemOrder::Relaxed)
896 emitMemOrderCaseLabel(builder, loc, order.getType(), caseOrders);
897 emitAtomicOpFn(actualOrder.value());
902 builder.createBreak(loc);
903 builder.setInsertionPointToEnd(switchBlock);
906 emitMemOrderCase( {});
907 emitMemOrderCase({cir::MemOrder::Relaxed});
908 emitMemOrderCase({cir::MemOrder::Consume, cir::MemOrder::Acquire});
909 emitMemOrderCase({cir::MemOrder::Release});
910 emitMemOrderCase({cir::MemOrder::AcquireRelease});
911 emitMemOrderCase({cir::MemOrder::SequentiallyConsistent});
918 const Expr *memOrder,
bool isStore,
bool isLoad,
bool isFence,
919 llvm::function_ref<
void(cir::MemOrder)> emitAtomicOpFn) {
923 uint64_t constOrder = eval.
Val.
getInt().getZExtValue();
928 cir::MemOrder oriOrder =
static_cast<cir::MemOrder
>(constOrder);
929 if (std::optional<cir::MemOrder> actualOrder =
931 emitAtomicOpFn(actualOrder.value());
946 memTy = ty->getValueType();
948 Expr *isWeakExpr =
nullptr;
949 Expr *orderFailExpr =
nullptr;
957 if (e->
getOp() == AtomicExpr::AO__c11_atomic_init) {
969 std::optional<Expr::EvalResult> scopeConst;
972 scopeConst.emplace(std::move(eval));
974 switch (e->
getOp()) {
979 case AtomicExpr::AO__c11_atomic_init:
980 llvm_unreachable(
"already handled above with emitAtomicInit");
982 case AtomicExpr::AO__atomic_load_n:
983 case AtomicExpr::AO__scoped_atomic_load_n:
984 case AtomicExpr::AO__c11_atomic_load:
985 case AtomicExpr::AO__atomic_test_and_set:
986 case AtomicExpr::AO__atomic_clear:
989 case AtomicExpr::AO__atomic_load:
990 case AtomicExpr::AO__scoped_atomic_load:
994 case AtomicExpr::AO__atomic_store:
995 case AtomicExpr::AO__scoped_atomic_store:
999 case AtomicExpr::AO__atomic_exchange:
1000 case AtomicExpr::AO__scoped_atomic_exchange:
1005 case AtomicExpr::AO__atomic_compare_exchange:
1006 case AtomicExpr::AO__atomic_compare_exchange_n:
1007 case AtomicExpr::AO__c11_atomic_compare_exchange_weak:
1008 case AtomicExpr::AO__c11_atomic_compare_exchange_strong:
1009 case AtomicExpr::AO__scoped_atomic_compare_exchange:
1010 case AtomicExpr::AO__scoped_atomic_compare_exchange_n:
1012 if (e->
getOp() == AtomicExpr::AO__atomic_compare_exchange ||
1013 e->
getOp() == AtomicExpr::AO__scoped_atomic_compare_exchange)
1018 if (e->
getOp() == AtomicExpr::AO__atomic_compare_exchange_n ||
1019 e->
getOp() == AtomicExpr::AO__atomic_compare_exchange ||
1020 e->
getOp() == AtomicExpr::AO__scoped_atomic_compare_exchange_n ||
1021 e->
getOp() == AtomicExpr::AO__scoped_atomic_compare_exchange)
1025 case AtomicExpr::AO__c11_atomic_fetch_add:
1026 case AtomicExpr::AO__c11_atomic_fetch_sub:
1029 "atomic fetch-and-add and fetch-and-sub for pointers");
1033 case AtomicExpr::AO__atomic_fetch_add:
1034 case AtomicExpr::AO__atomic_fetch_max:
1035 case AtomicExpr::AO__atomic_fetch_min:
1036 case AtomicExpr::AO__atomic_fetch_sub:
1037 case AtomicExpr::AO__atomic_add_fetch:
1038 case AtomicExpr::AO__atomic_max_fetch:
1039 case AtomicExpr::AO__atomic_min_fetch:
1040 case AtomicExpr::AO__atomic_sub_fetch:
1041 case AtomicExpr::AO__c11_atomic_fetch_max:
1042 case AtomicExpr::AO__c11_atomic_fetch_min:
1043 case AtomicExpr::AO__scoped_atomic_fetch_add:
1044 case AtomicExpr::AO__scoped_atomic_fetch_max:
1045 case AtomicExpr::AO__scoped_atomic_fetch_min:
1046 case AtomicExpr::AO__scoped_atomic_fetch_sub:
1047 case AtomicExpr::AO__scoped_atomic_add_fetch:
1048 case AtomicExpr::AO__scoped_atomic_max_fetch:
1049 case AtomicExpr::AO__scoped_atomic_min_fetch:
1050 case AtomicExpr::AO__scoped_atomic_sub_fetch:
1053 case AtomicExpr::AO__atomic_fetch_and:
1054 case AtomicExpr::AO__atomic_fetch_nand:
1055 case AtomicExpr::AO__atomic_fetch_or:
1056 case AtomicExpr::AO__atomic_fetch_xor:
1057 case AtomicExpr::AO__atomic_and_fetch:
1058 case AtomicExpr::AO__atomic_nand_fetch:
1059 case AtomicExpr::AO__atomic_or_fetch:
1060 case AtomicExpr::AO__atomic_xor_fetch:
1061 case AtomicExpr::AO__atomic_exchange_n:
1062 case AtomicExpr::AO__atomic_store_n:
1063 case AtomicExpr::AO__c11_atomic_fetch_and:
1064 case AtomicExpr::AO__c11_atomic_fetch_nand:
1065 case AtomicExpr::AO__c11_atomic_fetch_or:
1066 case AtomicExpr::AO__c11_atomic_fetch_xor:
1067 case AtomicExpr::AO__c11_atomic_exchange:
1068 case AtomicExpr::AO__c11_atomic_store:
1069 case AtomicExpr::AO__scoped_atomic_fetch_and:
1070 case AtomicExpr::AO__scoped_atomic_fetch_nand:
1071 case AtomicExpr::AO__scoped_atomic_fetch_or:
1072 case AtomicExpr::AO__scoped_atomic_fetch_xor:
1073 case AtomicExpr::AO__scoped_atomic_and_fetch:
1074 case AtomicExpr::AO__scoped_atomic_nand_fetch:
1075 case AtomicExpr::AO__scoped_atomic_or_fetch:
1076 case AtomicExpr::AO__scoped_atomic_xor_fetch:
1077 case AtomicExpr::AO__scoped_atomic_store_n:
1078 case AtomicExpr::AO__scoped_atomic_exchange_n:
1079 case AtomicExpr::AO__atomic_fetch_uinc:
1080 case AtomicExpr::AO__atomic_fetch_udec:
1081 case AtomicExpr::AO__scoped_atomic_fetch_uinc:
1082 case AtomicExpr::AO__scoped_atomic_fetch_udec:
1089 bool shouldCastToIntPtrTy =
1098 if (shouldCastToIntPtrTy) {
1099 ptr = atomics.castToAtomicIntPointer(ptr);
1101 val1 = atomics.convertToAtomicIntPointer(val1);
1104 if (shouldCastToIntPtrTy)
1105 dest = atomics.castToAtomicIntPointer(dest);
1108 }
else if (e->
getOp() == AtomicExpr::AO__atomic_test_and_set) {
1110 "test_and_set.bool");
1112 dest = atomics.createTempAlloca();
1113 if (shouldCastToIntPtrTy)
1114 dest = atomics.castToAtomicIntPointer(dest);
1117 bool powerOf2Size = (size & (size - 1)) == 0;
1118 bool useLibCall = !powerOf2Size || (size > 16);
1135 bool isStore = e->
getOp() == AtomicExpr::AO__c11_atomic_store ||
1136 e->
getOp() == AtomicExpr::AO__opencl_atomic_store ||
1137 e->
getOp() == AtomicExpr::AO__hip_atomic_store ||
1138 e->
getOp() == AtomicExpr::AO__atomic_store ||
1139 e->
getOp() == AtomicExpr::AO__atomic_store_n ||
1140 e->
getOp() == AtomicExpr::AO__scoped_atomic_store ||
1141 e->
getOp() == AtomicExpr::AO__scoped_atomic_store_n ||
1142 e->
getOp() == AtomicExpr::AO__atomic_clear;
1143 bool isLoad = e->
getOp() == AtomicExpr::AO__c11_atomic_load ||
1144 e->
getOp() == AtomicExpr::AO__opencl_atomic_load ||
1145 e->
getOp() == AtomicExpr::AO__hip_atomic_load ||
1146 e->
getOp() == AtomicExpr::AO__atomic_load ||
1147 e->
getOp() == AtomicExpr::AO__atomic_load_n ||
1148 e->
getOp() == AtomicExpr::AO__scoped_atomic_load ||
1149 e->
getOp() == AtomicExpr::AO__scoped_atomic_load_n;
1151 auto emitAtomicOpCallBackFn = [&](cir::MemOrder memOrder) {
1152 emitAtomicOp(*
this, e, dest, ptr, val1, val2, isWeakExpr, orderFailExpr,
1153 size, memOrder, scopeConst, scope);
1156 emitAtomicOpCallBackFn);
1168 auto order = cir::MemOrder::SequentiallyConsistent;
1181 cir::MemOrder order,
bool isVolatile,
1185 mlir::Location loc = dest.
getPointer().getLoc();
1190 AtomicInfo atomics(*
this, dest, loc);
1191 LValue lvalue = atomics.getAtomicLValue();
1196 atomics.emitCopyIntoMemory(rvalue);
1201 if (atomics.shouldUseLibCall()) {
1203 cgm.errorNYI(loc,
"emitAtomicStore: atomic store with library call");
1208 mlir::Value valueToStore = atomics.convertRValueToInt(rvalue);
1211 Address addr = atomics.getAtomicAddress();
1212 if (mlir::Value value = atomics.getScalarRValValueOrNull(rvalue)) {
1214 addr = atomics.castToAtomicIntPointer(addr);
1219 cir::StoreOp store = builder.createStore(loc, valueToStore, addr);
1224 store.setMemOrder(order);
1229 store.setIsVolatile(
true);
1235 cgm.errorNYI(loc,
"emitAtomicStore: non-simple atomic lvalue");
1242 switch (atomics.getEvaluationKind()) {
1258 bool zeroed =
false;
1260 zeroed = atomics.emitMemSetZeroIfNecessary();
1261 dest = atomics.projectValue();
1276 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 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)
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.
@ 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.