clang 24.0.0git
CIRGenAtomic.cpp
Go to the documentation of this file.
1//===--- CIRGenAtomic.cpp - Emit CIR for atomic operations ----------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file contains the code for emitting atomic operations.
10//
11//===----------------------------------------------------------------------===//
12
13#include "CIRGenFunction.h"
15
16using namespace clang;
17using namespace clang::CIRGen;
18using namespace cir;
19
20namespace {
21class AtomicInfo {
22 CIRGenFunction &cgf;
23 QualType atomicTy;
24 QualType valueTy;
25 uint64_t atomicSizeInBits = 0;
26 uint64_t valueSizeInBits = 0;
27 CharUnits atomicAlign;
28 CharUnits valueAlign;
29 TypeEvaluationKind evaluationKind = cir::TEK_Scalar;
30 bool useLibCall = true;
31 LValue lvalue;
32 mlir::Location loc;
33
34public:
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();
43 else
44 valueTy = atomicTy;
45 evaluationKind = cgf.getEvaluationKind(valueTy);
46
47 TypeInfo valueTypeInfo = ctx.getTypeInfo(valueTy);
48 TypeInfo atomicTypeInfo = ctx.getTypeInfo(atomicTy);
49 uint64_t valueAlignInBits = valueTypeInfo.Align;
50 uint64_t atomicAlignInBits = atomicTypeInfo.Align;
51 valueSizeInBits = valueTypeInfo.Width;
52 atomicSizeInBits = atomicTypeInfo.Width;
53 assert(valueSizeInBits <= atomicSizeInBits);
54 assert(valueAlignInBits <= atomicAlignInBits);
55
56 atomicAlign = ctx.toCharUnitsFromBits(atomicAlignInBits);
57 valueAlign = ctx.toCharUnitsFromBits(valueAlignInBits);
58 if (lvalue.getAlignment().isZero())
59 lvalue.setAlignment(atomicAlign);
60
61 this->lvalue = lvalue;
62 } else {
64 cgf.cgm.errorNYI(loc, "AtomicInfo: non-simple lvalue");
65 }
66 useLibCall = !ctx.getTargetInfo().hasBuiltinAtomic(
67 atomicSizeInBits, ctx.toBits(lvalue.getAlignment()));
68 }
69
70 QualType getValueType() const { return valueTy; }
71 QualType getAtomicType() const { return atomicTy; }
72 CharUnits getAtomicAlignment() const { return atomicAlign; }
73 TypeEvaluationKind getEvaluationKind() const { return evaluationKind; }
74 mlir::Value getAtomicPointer() const {
75 if (lvalue.isSimple())
76 return lvalue.getPointer();
78 return nullptr;
79 }
80 bool shouldUseLibCall() const { return useLibCall; }
81 const LValue &getAtomicLValue() const { return lvalue; }
82 Address getAtomicAddress() const {
83 mlir::Type elemTy;
84 if (lvalue.isSimple()) {
85 elemTy = lvalue.getAddress().getElementType();
86 } else {
88 cgf.cgm.errorNYI(loc, "AtomicInfo::getAtomicAddress: non-simple lvalue");
89 }
90 return Address(getAtomicPointer(), elemTy, getAtomicAlignment());
91 }
92
93 /// Is the atomic size larger than the underlying value type?
94 ///
95 /// Note that the absence of padding does not mean that atomic
96 /// objects are completely interchangeable with non-atomic
97 /// objects: we might have promoted the alignment of a type
98 /// without making it bigger.
99 bool hasPadding() const { return (valueSizeInBits != atomicSizeInBits); }
100
101 bool emitMemSetZeroIfNecessary() const;
102
103 mlir::Value getScalarRValValueOrNull(RValue rvalue) const;
104
105 /// Cast the given pointer to an integer pointer suitable for atomic
106 /// operations on the source.
107 Address castToAtomicIntPointer(Address addr) const;
108
109 /// If addr is compatible with the iN that will be used for an atomic
110 /// operation, bitcast it. Otherwise, create a temporary that is suitable and
111 /// copy the value across.
112 Address convertToAtomicIntPointer(Address addr, mlir::Location loc) const;
113
114 /// Turn an atomic-layout object into an r-value.
115 RValue convertAtomicTempToRValue(Address addr, AggValueSlot resultSlot,
116 SourceLocation loc, bool asValue) const;
117
118 /// Converts a rvalue to integer value.
119 mlir::Value convertRValueToInt(RValue rvalue, mlir::Location loc,
120 bool cmpxchg = false) const;
121
122 RValue convertToValueOrAtomic(mlir::Value intVal, AggValueSlot resultSlot,
123 SourceLocation loc, bool asValue,
124 bool cmpxchg = false) const;
125
126 /// Copy an atomic r-value into atomic-layout memory.
127 void emitCopyIntoMemory(RValue rvalue) const;
128
129 /// Project an l-value down to the value field.
130 LValue projectValue() const {
131 assert(lvalue.isSimple());
132 Address addr = getAtomicAddress();
133 if (hasPadding())
134 addr = cgf.getBuilder().createGetMember(loc, addr, /*name=*/"value",
135 /*index=*/0);
136
138 return LValue::makeAddr(addr, getValueType(), lvalue.getBaseInfo());
139 }
140
141 /// Emits atomic load.
142 /// \returns Loaded value.
143 RValue emitAtomicLoad(AggValueSlot resultSlot, SourceLocation loc,
144 bool asValue, cir::MemOrder order, bool isVolatile);
145
146 /// Materialize an atomic r-value in atomic-layout memory.
147 Address materializeRValue(RValue rvalue, mlir::Location loc) const;
148
149 /// Creates temp alloca for intermediate operations on atomic value.
150 Address createTempAlloca() const;
151
152private:
153 bool requiresMemSetZero(mlir::Type ty) const;
154
155 /// Emits atomic load as a CIR operation.
156 mlir::Value emitAtomicLoadOp(cir::MemOrder order, bool isVolatile,
157 bool cmpxchg = false);
158};
159} // namespace
160
161// This function emits any expression (scalar, complex, or aggregate)
162// into a temporary alloca.
164 Address declPtr = cgf.createMemTemp(
165 e->getType(), cgf.getLoc(e->getSourceRange()), ".atomictmp");
166 cgf.emitAnyExprToMem(e, declPtr, e->getType().getQualifiers(),
167 /*Init*/ true);
168 return declPtr;
169}
170
171/// Does a store of the given IR type modify the full expected width?
172static bool isFullSizeType(CIRGenModule &cgm, mlir::Type ty,
173 uint64_t expectedSize) {
174 return cgm.getDataLayout().getTypeStoreSize(ty) * 8 == expectedSize;
175}
176
177/// Does the atomic type require memsetting to zero before initialization?
178///
179/// The IR type is provided as a way of making certain queries faster.
180bool AtomicInfo::requiresMemSetZero(mlir::Type ty) const {
181 // If the atomic type has size padding, we definitely need a memset.
182 if (hasPadding())
183 return true;
184
185 // Otherwise, do some simple heuristics to try to avoid it:
186 switch (getEvaluationKind()) {
187 // For scalars and complexes, check whether the store size of the
188 // type uses the full size.
189 case cir::TEK_Scalar:
190 return !isFullSizeType(cgf.cgm, ty, atomicSizeInBits);
191 case cir::TEK_Complex:
192 return !isFullSizeType(cgf.cgm,
193 mlir::cast<cir::ComplexType>(ty).getElementType(),
194 atomicSizeInBits / 2);
195 // Padding in structs has an undefined bit pattern. User beware.
197 return false;
198 }
199 llvm_unreachable("bad evaluation kind");
200}
201
202Address AtomicInfo::convertToAtomicIntPointer(Address addr,
203 mlir::Location loc) const {
204 mlir::Type ty = addr.getElementType();
205 uint64_t sourceSizeInBits = cgf.cgm.getDataLayout().getTypeSizeInBits(ty);
206 if (sourceSizeInBits != atomicSizeInBits) {
207 CIRGenBuilderTy &builder = cgf.getBuilder();
208
209 Address tmp = createTempAlloca();
210 mlir::Value zero = builder.getConstInt(loc, cgf.cgm.uInt8Ty, 0);
211 unsigned size =
212 cgf.getContext().toCharUnitsFromBits(atomicSizeInBits).getQuantity();
213 mlir::Value memSetSize = builder.getConstInt(loc, cgf.cgm.uInt64Ty, size);
214 addr = addr.withElementType(builder, cgf.cgm.voidTy);
215 builder.createMemSet(loc, addr, zero, memSetSize);
216
217 tmp = tmp.withElementType(builder, cgf.cgm.voidTy);
218 builder.createMemCpy(
219 loc, tmp, addr,
220 builder.getConstInt(loc, cgf.cgm.uInt64Ty,
221 std::min(atomicSizeInBits, sourceSizeInBits) / 8));
222 addr = tmp;
223 }
224
225 return castToAtomicIntPointer(addr);
226}
227
228RValue AtomicInfo::convertAtomicTempToRValue(Address addr,
229 AggValueSlot resultSlot,
230 SourceLocation loc,
231 bool asValue) const {
232 if (lvalue.isSimple()) {
233 if (evaluationKind == TEK_Aggregate)
234 return resultSlot.asRValue();
235
236 // Drill into the padding structure if we have one.
237 if (hasPadding()) {
238 cgf.cgm.errorNYI(loc,
239 "AtomicInfo::convertAtomicTempToRValue: hasPadding");
240 return RValue::get(nullptr);
241 }
242
243 // Otherwise, just convert the temporary to an r-value using the
244 // normal conversion routine.
245 return cgf.convertTempToRValue(addr, getValueType(), loc);
246 }
247
248 cgf.cgm.errorNYI(
249 loc, "AtomicInfo::convertAtomicTempToRValue: lvalue is not simple");
250 return RValue::get(nullptr);
251}
252
253RValue AtomicInfo::emitAtomicLoad(AggValueSlot resultSlot, SourceLocation loc,
254 bool asValue, cir::MemOrder order,
255 bool isVolatile) {
256 // Check whether we should use a library call.
257 if (shouldUseLibCall()) {
259 cgf.cgm.errorNYI(loc, "emitAtomicLoad: emit atomic lib call");
260 return RValue::get(nullptr);
261 }
262
263 // Okay, we're doing this natively.
264 mlir::Value loadOp = emitAtomicLoadOp(order, isVolatile);
265
266 // If we're ignoring an aggregate return, don't do anything.
267 if (getEvaluationKind() == TEK_Aggregate && resultSlot.isIgnored())
268 return RValue::getAggregate(Address::invalid(), false);
269
270 // Okay, turn that back into the original value or atomic (for non-simple
271 // lvalues) type.
272 return convertToValueOrAtomic(loadOp, resultSlot, loc, asValue);
273}
274
275Address AtomicInfo::createTempAlloca() const {
276 // Remove addrspace info from the atomic pointer element when making the
277 // alloca pointer element.
278 QualType tmpTy = (lvalue.isBitField() && valueSizeInBits > atomicSizeInBits)
279 ? valueTy
280 : atomicTy.getUnqualifiedType();
281 Address tempAlloca =
282 cgf.createMemTemp(tmpTy, getAtomicAlignment(), loc, "atomic-temp");
283
284 // Cast to pointer to value type for bitfields.
285 if (lvalue.isBitField()) {
286 cgf.cgm.errorNYI(loc, "AtomicInfo::createTempAlloca: bitfield lvalue");
287 }
288
289 return tempAlloca;
290}
291
292mlir::Value AtomicInfo::getScalarRValValueOrNull(RValue rvalue) const {
293 if (rvalue.isScalar() && (!hasPadding() || !lvalue.isSimple()))
294 return rvalue.getValue();
295 return nullptr;
296}
297
298Address AtomicInfo::castToAtomicIntPointer(Address addr) const {
299 auto intTy = mlir::dyn_cast<cir::IntType>(addr.getElementType());
300 // Don't bother with int casts if the integer size is the same.
301 if (intTy && intTy.getWidth() == atomicSizeInBits)
302 return addr;
303 auto ty = cgf.getBuilder().getUIntNTy(atomicSizeInBits);
304 return addr.withElementType(cgf.getBuilder(), ty);
305}
306
307bool AtomicInfo::emitMemSetZeroIfNecessary() const {
308 assert(lvalue.isSimple());
309 Address addr = lvalue.getAddress();
310 if (!requiresMemSetZero(addr.getElementType()))
311 return false;
312
313 addr = addr.withElementType(cgf.getBuilder(), cgf.cgm.voidTy);
314 mlir::Value zero = cgf.getBuilder().getConstInt(loc, cgf.cgm.uInt8Ty, 0);
315 mlir::Value memSetSize = cgf.getBuilder().getConstInt(
316 loc, cgf.cgm.uInt64Ty,
317 cgf.getContext().toCharUnitsFromBits(atomicSizeInBits).getQuantity());
318
319 cgf.getBuilder().createMemSet(loc, addr, zero, memSetSize);
320 return true;
321}
322
323/// Return true if \param valueTy is a type that should be casted to integer
324/// around the atomic memory operation. If \param cmpxchg is true, then the
325/// cast of a floating point type is made as that instruction can not have
326/// floating point operands. TODO: Allow compare-and-exchange and FP - see
327/// comment in CIRGenAtomicExpandPass.cpp.
328static bool shouldCastToInt(mlir::Type valueTy, bool cmpxchg) {
329 if (cir::isAnyFloatingPointType(valueTy))
330 return isa<cir::FP80Type>(valueTy) || cmpxchg;
331 return !isa<cir::IntType>(valueTy) && !isa<cir::PointerType>(valueTy);
332}
333
334mlir::Value AtomicInfo::emitAtomicLoadOp(cir::MemOrder order, bool isVolatile,
335 bool cmpxchg) {
336 Address addr = getAtomicAddress();
337 if (shouldCastToInt(addr.getElementType(), cmpxchg))
338 addr = castToAtomicIntPointer(addr);
339
340 cir::LoadOp op =
341 cgf.getBuilder().createLoad(loc, addr, /*isVolatile=*/isVolatile);
342 op.setMemOrder(order);
343
345 return op;
346}
347
348mlir::Value AtomicInfo::convertRValueToInt(RValue rvalue, mlir::Location loc,
349 bool cmpxchg) const {
350 // If we've got a scalar value of the right size, try to avoid going
351 // through memory. Floats get casted if needed by AtomicExpandPass.
352 if (mlir::Value value = getScalarRValValueOrNull(rvalue)) {
353 if (!shouldCastToInt(value.getType(), cmpxchg))
354 return cgf.emitToMemory(value, valueTy);
355
356 cgf.cgm.errorNYI(
357 loc, "AtomicInfo::convertRValueToInt: cast scalar rvalue to int");
358 return nullptr;
359 }
360
361 // Otherwise, we need to go through memory.
362 // Put the r-value in memory.
363 Address addr = materializeRValue(rvalue, loc);
364
365 // Cast the temporary to the atomic int type and pull a value out.
366 addr = castToAtomicIntPointer(addr);
367
368 return cgf.getBuilder().createLoad(loc, addr);
369}
370
371RValue AtomicInfo::convertToValueOrAtomic(mlir::Value intVal,
372 AggValueSlot resultSlot,
373 SourceLocation loc, bool asValue,
374 bool cmpxchg) const {
375 // Try not to in some easy cases.
376 assert((mlir::isa<cir::IntType, cir::PointerType, cir::FPTypeInterface>(
377 intVal.getType())) &&
378 "Expected integer, pointer or floating point value when converting "
379 "result.");
380 bool isWholeValue =
381 !lvalue.isBitField() || lvalue.getBitFieldInfo().size == valueSizeInBits;
382 if (getEvaluationKind() == TEK_Scalar &&
383 ((isWholeValue && !hasPadding()) || !asValue)) {
384 mlir::Type valTy = asValue ? cgf.convertTypeForMem(valueTy)
385 : getAtomicAddress().getElementType();
386 if (!shouldCastToInt(valTy, cmpxchg)) {
387 assert((!mlir::isa<cir::IntType>(valTy) || intVal.getType() == valTy) &&
388 "Different integer types.");
389 return RValue::get(cgf.emitFromMemory(intVal, valueTy));
390 }
391
392 cgf.cgm.errorNYI("convertToValueOrAtomic: convert through bitcast");
393 return RValue::get(nullptr);
394 }
395
396 // Create a temporary. This needs to be big enough to hold the
397 // atomic integer.
398 Address temp = Address::invalid();
399 bool tempIsVolatile = false;
400 if (asValue && getEvaluationKind() == TEK_Aggregate) {
401 assert(!resultSlot.isIgnored());
402 temp = resultSlot.getAddress();
403 tempIsVolatile = resultSlot.isVolatile();
404 } else {
405 temp = createTempAlloca();
406 }
407
408 // Slam the integer into the temporary.
409 Address castTemp = castToAtomicIntPointer(temp);
410 cgf.getBuilder().createStore(cgf.getLoc(loc), intVal, castTemp,
411 tempIsVolatile);
412 return convertAtomicTempToRValue(temp, resultSlot, loc, asValue);
413}
414
415/// Copy an r-value into memory as part of storing to an atomic type.
416/// This needs to create a bit-pattern suitable for atomic operations.
417void AtomicInfo::emitCopyIntoMemory(RValue rvalue) const {
418 assert(lvalue.isSimple());
419
420 // If we have an r-value, the rvalue should be of the atomic type,
421 // which means that the caller is responsible for having zeroed
422 // any padding. Just do an aggregate copy of that type.
423 if (rvalue.isAggregate()) {
424 cgf.cgm.errorNYI("copying aggregate into atomic lvalue");
425 return;
426 }
427
428 // Okay, otherwise we're copying stuff.
429
430 // Zero out the buffer if necessary.
431 emitMemSetZeroIfNecessary();
432
433 // Drill past the padding if present.
434 LValue tempLValue = projectValue();
435
436 // Okay, store the rvalue in.
437 if (rvalue.isScalar()) {
438 cgf.emitStoreOfScalar(rvalue.getValue(), tempLValue, /*isInit=*/true);
439 } else {
440 cgf.emitStoreOfComplex(loc, rvalue.getComplexValue(), tempLValue,
441 /*isInit=*/true);
442 }
443}
444
445/// Materialize an r-value into memory for the purposes of storing it
446/// to an atomic type.
447Address AtomicInfo::materializeRValue(RValue rvalue, mlir::Location loc) const {
448 // Aggregate r-values are already in memory, and EmitAtomicStore
449 // requires them to be values of the atomic type.
450 if (rvalue.isAggregate())
451 return rvalue.getAggregateAddress();
452
453 // Otherwise, make a temporary and materialize into it.
454 LValue tempLV = cgf.makeAddrLValue(createTempAlloca(), getAtomicType());
455 AtomicInfo atomics(cgf, tempLV, loc);
456
457 atomics.emitCopyIntoMemory(rvalue);
458 return tempLV.getAddress();
459}
460
461static void emitDefaultCaseLabel(CIRGenBuilderTy &builder, mlir::Location loc) {
462 mlir::ArrayAttr valuesAttr = builder.getArrayAttr({});
463 mlir::OpBuilder::InsertPoint insertPoint;
464 cir::CaseOp::create(builder, loc, valuesAttr, cir::CaseOpKind::Default,
465 insertPoint);
466 builder.restoreInsertionPoint(insertPoint);
467}
468
469// Create a "case" operation with the given list of orders as its values. Also
470// create the region that will hold the body of the switch-case label.
471static void emitMemOrderCaseLabel(CIRGenBuilderTy &builder, mlir::Location loc,
472 mlir::Type orderType,
475 for (cir::MemOrder order : orders)
476 orderAttrs.push_back(cir::IntAttr::get(orderType, static_cast<int>(order)));
477 mlir::ArrayAttr ordersAttr = builder.getArrayAttr(orderAttrs);
478
479 mlir::OpBuilder::InsertPoint insertPoint;
480 cir::CaseOp::create(builder, loc, ordersAttr, cir::CaseOpKind::Anyof,
481 insertPoint);
482 builder.restoreInsertionPoint(insertPoint);
483}
484
485static void emitAtomicCmpXchg(CIRGenFunction &cgf, AtomicExpr *e, bool isWeak,
486 Address dest, Address ptr, Address val1,
487 Address val2, uint64_t size,
488 cir::MemOrder successOrder,
489 cir::MemOrder failureOrder,
490 cir::SyncScopeKind scope) {
491 mlir::Location loc = cgf.getLoc(e->getSourceRange());
492
493 CIRGenBuilderTy &builder = cgf.getBuilder();
494 mlir::Value expected = builder.createLoad(loc, val1);
495 mlir::Value desired = builder.createLoad(loc, val2);
496
497 auto cmpxchg = cir::AtomicCmpXchgOp::create(
498 builder, loc, expected.getType(), builder.getBoolTy(), ptr.getPointer(),
499 expected, desired,
500 cir::MemOrderAttr::get(&cgf.getMLIRContext(), successOrder),
501 cir::MemOrderAttr::get(&cgf.getMLIRContext(), failureOrder),
502 cir::SyncScopeKindAttr::get(&cgf.getMLIRContext(), scope),
503 builder.getI64IntegerAttr(ptr.getAlignment().getAsAlign().value()));
504
505 cmpxchg.setIsVolatile(e->isVolatile());
506 cmpxchg.setWeak(isWeak);
507
508 mlir::Value failed = builder.createNot(cmpxchg.getSuccess());
509 cir::IfOp::create(builder, loc, failed, /*withElseRegion=*/false,
510 [&](mlir::OpBuilder &, mlir::Location) {
511 auto ptrTy = mlir::cast<cir::PointerType>(
512 val1.getPointer().getType());
513 if (val1.getElementType() != ptrTy.getPointee()) {
514 val1 = val1.withPointer(builder.createPtrBitcast(
515 val1.getPointer(), val1.getElementType()));
516 }
517 builder.createStore(loc, cmpxchg.getOld(), val1);
518 builder.createYield(loc);
519 });
520
521 // Update the memory at Dest with Success's value.
522 cgf.emitStoreOfScalar(cmpxchg.getSuccess(),
523 cgf.makeAddrLValue(dest, e->getType()),
524 /*isInit=*/false);
525}
526
528 bool isWeak, Address dest, Address ptr,
529 Address val1, Address val2,
530 Expr *failureOrderExpr, uint64_t size,
531 cir::MemOrder successOrder,
532 cir::SyncScopeKind scope) {
533 Expr::EvalResult failureOrderEval;
534 if (failureOrderExpr->EvaluateAsInt(failureOrderEval, cgf.getContext())) {
535 uint64_t failureOrderInt = failureOrderEval.Val.getInt().getZExtValue();
536
537 cir::MemOrder failureOrder;
538 if (!cir::isValidCIRAtomicOrderingCABI(failureOrderInt)) {
539 failureOrder = cir::MemOrder::Relaxed;
540 } else {
541 switch ((cir::MemOrder)failureOrderInt) {
542 case cir::MemOrder::Relaxed:
543 // 31.7.2.18: "The failure argument shall not be memory_order_release
544 // nor memory_order_acq_rel". Fallback to monotonic.
545 case cir::MemOrder::Release:
546 case cir::MemOrder::AcquireRelease:
547 failureOrder = cir::MemOrder::Relaxed;
548 break;
549 case cir::MemOrder::Consume:
550 case cir::MemOrder::Acquire:
551 failureOrder = cir::MemOrder::Acquire;
552 break;
553 case cir::MemOrder::SequentiallyConsistent:
554 failureOrder = cir::MemOrder::SequentiallyConsistent;
555 break;
556 }
557 }
558
559 // Prior to c++17, "the failure argument shall be no stronger than the
560 // success argument". This condition has been lifted and the only
561 // precondition is 31.7.2.18. Effectively treat this as a DR and skip
562 // language version checks.
563 emitAtomicCmpXchg(cgf, e, isWeak, dest, ptr, val1, val2, size, successOrder,
564 failureOrder, scope);
565 return;
566 }
567
568 // The failure memory order is not a compile time constant. The CIR atomic ops
569 // require a constant value, so that memory order is known at compile time. In
570 // this case, we can switch based on the memory order and call each variant
571 // individually.
572 mlir::Value failureOrderVal = cgf.emitScalarExpr(failureOrderExpr);
573 mlir::Location atomicLoc = cgf.getLoc(e->getSourceRange());
574 cir::SwitchOp::create(
575 cgf.getBuilder(), atomicLoc, failureOrderVal,
576 [&](mlir::OpBuilder &b, mlir::Location loc, mlir::OperationState &os) {
577 mlir::Block *switchBlock = cgf.getBuilder().getBlock();
578
579 // case cir::MemOrder::Relaxed:
580 // // 31.7.2.18: "The failure argument shall not be
581 // memory_order_release
582 // // nor memory_order_acq_rel". Fallback to monotonic.
583 // case cir::MemOrder::Release:
584 // case cir::MemOrder::AcquireRelease:
585 // Note: Since there are 3 options, this makes sense to just emit as a
586 // 'default', which prevents user code from 'falling off' of this,
587 // which seems reasonable. Also, 'relaxed' being the default behavior
588 // is also probably the least harmful.
589 emitDefaultCaseLabel(cgf.getBuilder(), atomicLoc);
590 emitAtomicCmpXchg(cgf, e, isWeak, dest, ptr, val1, val2, size,
591 successOrder, cir::MemOrder::Relaxed, scope);
592 cgf.getBuilder().createBreak(atomicLoc);
593 cgf.getBuilder().setInsertionPointToEnd(switchBlock);
594
595 // case cir::MemOrder::Consume:
596 // case cir::MemOrder::Acquire:
597 emitMemOrderCaseLabel(cgf.getBuilder(), loc, failureOrderVal.getType(),
598 {cir::MemOrder::Consume, cir::MemOrder::Acquire});
599 emitAtomicCmpXchg(cgf, e, isWeak, dest, ptr, val1, val2, size,
600 successOrder, cir::MemOrder::Acquire, scope);
601 cgf.getBuilder().createBreak(atomicLoc);
602 cgf.getBuilder().setInsertionPointToEnd(switchBlock);
603
604 // case cir::MemOrder::SequentiallyConsistent:
605 emitMemOrderCaseLabel(cgf.getBuilder(), loc, failureOrderVal.getType(),
606 {cir::MemOrder::SequentiallyConsistent});
607 emitAtomicCmpXchg(cgf, e, isWeak, dest, ptr, val1, val2, size,
608 successOrder, cir::MemOrder::SequentiallyConsistent,
609 scope);
610 cgf.getBuilder().createBreak(atomicLoc);
611 cgf.getBuilder().setInsertionPointToEnd(switchBlock);
612
613 cgf.getBuilder().createYield(atomicLoc);
614 });
615}
616
617// A version of the emitAtomicCmpXchgFailureSet function that ALSO checks
618// whether it is 'weak' or not (by adding an 'if' around it, and calling
619// emitAtomicCmpXchgFailureSet 2x).
621 CIRGenFunction &cgf, AtomicExpr *e, Expr *isWeakExpr, Address dest,
622 Address ptr, Address val1, Address val2, Expr *failureOrderExpr,
623 uint64_t size, cir::MemOrder successOrder, cir::SyncScopeKind scope) {
624 mlir::Value isWeakVal = cgf.emitScalarExpr(isWeakExpr);
625 // The AST seems to be inserting a 'bool' cast (even in C mode) here, so we'll
626 // just emit it like a scalar.
627 assert(isWeakVal.getType() == cgf.getBuilder().getBoolTy());
628 mlir::Location atomicLoc = cgf.getLoc(e->getSourceRange());
629
630 // Unlike classic compiler, we use an 'if' here instead of a switch, simply to
631 // make this more readable/logical, plus we don't allow switch over a bool in
632 // CIR.
633 cir::IfOp::create(
634 cgf.getBuilder(), atomicLoc, isWeakVal, /*elseRegion=*/true,
635 [&](mlir::OpBuilder &b, mlir::Location loc) {
636 emitAtomicCmpXchgFailureSet(cgf, e, /*isWeak=*/true, dest, ptr, val1,
637 val2, failureOrderExpr, size, successOrder,
638 scope);
639 cgf.getBuilder().createYield(atomicLoc);
640 },
641 [&](mlir::OpBuilder &b, mlir::Location loc) {
642 emitAtomicCmpXchgFailureSet(cgf, e, /*isWeak=*/false, dest, ptr, val1,
643 val2, failureOrderExpr, size, successOrder,
644 scope);
645 cgf.getBuilder().createYield(atomicLoc);
646 });
647}
648
650 Address ptr, Address val1, Address val2,
651 Expr *isWeakExpr, Expr *failureOrderExpr, int64_t size,
652 cir::MemOrder order, cir::SyncScopeKind scope) {
654 llvm::StringRef opName;
655
656 CIRGenBuilderTy &builder = cgf.getBuilder();
657 mlir::Location loc = cgf.getLoc(expr->getSourceRange());
658 auto orderAttr = cir::MemOrderAttr::get(builder.getContext(), order);
659 auto scopeAttr = cir::SyncScopeKindAttr::get(builder.getContext(), scope);
660 cir::AtomicFetchKindAttr fetchAttr;
661 bool fetchFirst = true;
662
663 auto handleFetchOp = [&](cir::AtomicFetchKind kind) {
664 opName = cir::AtomicFetchOp::getOperationName();
665 fetchAttr = cir::AtomicFetchKindAttr::get(builder.getContext(), kind);
666 };
667
668 switch (expr->getOp()) {
669 case AtomicExpr::AO__c11_atomic_init:
670 llvm_unreachable("already handled!");
671
672 case AtomicExpr::AO__c11_atomic_compare_exchange_strong:
673 case AtomicExpr::AO__hip_atomic_compare_exchange_strong:
674 case AtomicExpr::AO__opencl_atomic_compare_exchange_strong:
675 emitAtomicCmpXchgFailureSet(cgf, expr, /*isWeak=*/false, dest, ptr, val1,
676 val2, failureOrderExpr, size, order, scope);
677 return;
678
679 case AtomicExpr::AO__c11_atomic_compare_exchange_weak:
680 case AtomicExpr::AO__hip_atomic_compare_exchange_weak:
681 case AtomicExpr::AO__opencl_atomic_compare_exchange_weak:
682 emitAtomicCmpXchgFailureSet(cgf, expr, /*isWeak=*/true, dest, ptr, val1,
683 val2, failureOrderExpr, size, order, scope);
684 return;
685
686 case AtomicExpr::AO__atomic_compare_exchange:
687 case AtomicExpr::AO__atomic_compare_exchange_n:
688 case AtomicExpr::AO__scoped_atomic_compare_exchange:
689 case AtomicExpr::AO__scoped_atomic_compare_exchange_n: {
690 bool isWeak = false;
691 if (isWeakExpr->EvaluateAsBooleanCondition(isWeak, cgf.getContext())) {
692 emitAtomicCmpXchgFailureSet(cgf, expr, isWeak, dest, ptr, val1, val2,
693 failureOrderExpr, size, order, scope);
694 } else {
695 emitAtomicCmpXchgFailureSetCheckWeak(cgf, expr, isWeakExpr, dest, ptr,
696 val1, val2, failureOrderExpr, size,
697 order, scope);
698 }
699 return;
700 }
701
702 case AtomicExpr::AO__c11_atomic_load:
703 case AtomicExpr::AO__atomic_load_n:
704 case AtomicExpr::AO__atomic_load:
705 case AtomicExpr::AO__scoped_atomic_load_n:
706 case AtomicExpr::AO__scoped_atomic_load:
707 case AtomicExpr::AO__hip_atomic_load:
708 case AtomicExpr::AO__opencl_atomic_load: {
709 cir::LoadOp load =
710 builder.createLoad(loc, ptr, /*isVolatile=*/expr->isVolatile());
711
712 load->setAttr("mem_order", orderAttr);
713 load->setAttr("sync_scope", scopeAttr);
714
715 builder.createStore(loc, load->getResult(0), dest);
716 return;
717 }
718
719 case AtomicExpr::AO__c11_atomic_store:
720 case AtomicExpr::AO__atomic_store_n:
721 case AtomicExpr::AO__atomic_store:
722 case AtomicExpr::AO__scoped_atomic_store:
723 case AtomicExpr::AO__scoped_atomic_store_n:
724 case AtomicExpr::AO__hip_atomic_store:
725 case AtomicExpr::AO__opencl_atomic_store: {
726 cir::LoadOp loadVal1 = builder.createLoad(loc, val1);
727
729
730 builder.createStore(loc, loadVal1, ptr, expr->isVolatile(),
731 /*isNontemporal=*/false,
732 /*align=*/mlir::IntegerAttr{}, scopeAttr, orderAttr);
733 return;
734 }
735
736 case AtomicExpr::AO__c11_atomic_exchange:
737 case AtomicExpr::AO__atomic_exchange_n:
738 case AtomicExpr::AO__atomic_exchange:
739 case AtomicExpr::AO__scoped_atomic_exchange_n:
740 case AtomicExpr::AO__scoped_atomic_exchange:
741 case AtomicExpr::AO__hip_atomic_exchange:
742 case AtomicExpr::AO__opencl_atomic_exchange:
743 opName = cir::AtomicXchgOp::getOperationName();
744 break;
745
746 case AtomicExpr::AO__atomic_add_fetch:
747 case AtomicExpr::AO__scoped_atomic_add_fetch:
748 fetchFirst = false;
749 [[fallthrough]];
750 case AtomicExpr::AO__c11_atomic_fetch_add:
751 case AtomicExpr::AO__atomic_fetch_add:
752 case AtomicExpr::AO__scoped_atomic_fetch_add:
753 case AtomicExpr::AO__hip_atomic_fetch_add:
754 case AtomicExpr::AO__opencl_atomic_fetch_add:
755 handleFetchOp(cir::AtomicFetchKind::Add);
756 break;
757
758 case AtomicExpr::AO__atomic_sub_fetch:
759 case AtomicExpr::AO__scoped_atomic_sub_fetch:
760 fetchFirst = false;
761 [[fallthrough]];
762 case AtomicExpr::AO__c11_atomic_fetch_sub:
763 case AtomicExpr::AO__atomic_fetch_sub:
764 case AtomicExpr::AO__scoped_atomic_fetch_sub:
765 case AtomicExpr::AO__hip_atomic_fetch_sub:
766 case AtomicExpr::AO__opencl_atomic_fetch_sub:
767 handleFetchOp(cir::AtomicFetchKind::Sub);
768 break;
769
770 case AtomicExpr::AO__atomic_min_fetch:
771 case AtomicExpr::AO__scoped_atomic_min_fetch:
772 fetchFirst = false;
773 [[fallthrough]];
774 case AtomicExpr::AO__c11_atomic_fetch_min:
775 case AtomicExpr::AO__atomic_fetch_min:
776 case AtomicExpr::AO__scoped_atomic_fetch_min:
777 case AtomicExpr::AO__hip_atomic_fetch_min:
778 case AtomicExpr::AO__opencl_atomic_fetch_min:
779 handleFetchOp(cir::AtomicFetchKind::Min);
780 break;
781
782 case AtomicExpr::AO__atomic_fetch_fminimum:
783 case AtomicExpr::AO__scoped_atomic_fetch_fminimum:
784 assert(expr->getValueType()->isFloatingType() &&
785 "fminimum operations only support floating-point types");
786 handleFetchOp(cir::AtomicFetchKind::Minimum);
787 break;
788
789 case AtomicExpr::AO__atomic_fetch_fminimum_num:
790 case AtomicExpr::AO__scoped_atomic_fetch_fminimum_num:
791 assert(expr->getValueType()->isFloatingType() &&
792 "fminimum_num operations only support floating-point types");
793 handleFetchOp(cir::AtomicFetchKind::MinimumNum);
794 break;
795
796 case AtomicExpr::AO__atomic_max_fetch:
797 case AtomicExpr::AO__scoped_atomic_max_fetch:
798 fetchFirst = false;
799 [[fallthrough]];
800 case AtomicExpr::AO__c11_atomic_fetch_max:
801 case AtomicExpr::AO__atomic_fetch_max:
802 case AtomicExpr::AO__scoped_atomic_fetch_max:
803 case AtomicExpr::AO__hip_atomic_fetch_max:
804 case AtomicExpr::AO__opencl_atomic_fetch_max:
805 handleFetchOp(cir::AtomicFetchKind::Max);
806 break;
807
808 case AtomicExpr::AO__atomic_fetch_fmaximum:
809 case AtomicExpr::AO__scoped_atomic_fetch_fmaximum:
810 assert(expr->getValueType()->isFloatingType() &&
811 "fmaximum operations only support floating-point types");
812 handleFetchOp(cir::AtomicFetchKind::Maximum);
813 break;
814
815 case AtomicExpr::AO__atomic_fetch_fmaximum_num:
816 case AtomicExpr::AO__scoped_atomic_fetch_fmaximum_num:
817 assert(expr->getValueType()->isFloatingType() &&
818 "fmaximum_num operations only support floating-point types");
819 handleFetchOp(cir::AtomicFetchKind::MaximumNum);
820 break;
821
822 case AtomicExpr::AO__atomic_and_fetch:
823 case AtomicExpr::AO__scoped_atomic_and_fetch:
824 fetchFirst = false;
825 [[fallthrough]];
826 case AtomicExpr::AO__c11_atomic_fetch_and:
827 case AtomicExpr::AO__atomic_fetch_and:
828 case AtomicExpr::AO__scoped_atomic_fetch_and:
829 case AtomicExpr::AO__hip_atomic_fetch_and:
830 case AtomicExpr::AO__opencl_atomic_fetch_and:
831 handleFetchOp(cir::AtomicFetchKind::And);
832 break;
833
834 case AtomicExpr::AO__atomic_or_fetch:
835 case AtomicExpr::AO__scoped_atomic_or_fetch:
836 fetchFirst = false;
837 [[fallthrough]];
838 case AtomicExpr::AO__c11_atomic_fetch_or:
839 case AtomicExpr::AO__atomic_fetch_or:
840 case AtomicExpr::AO__scoped_atomic_fetch_or:
841 case AtomicExpr::AO__hip_atomic_fetch_or:
842 case AtomicExpr::AO__opencl_atomic_fetch_or:
843 handleFetchOp(cir::AtomicFetchKind::Or);
844 break;
845
846 case AtomicExpr::AO__atomic_xor_fetch:
847 case AtomicExpr::AO__scoped_atomic_xor_fetch:
848 fetchFirst = false;
849 [[fallthrough]];
850 case AtomicExpr::AO__c11_atomic_fetch_xor:
851 case AtomicExpr::AO__atomic_fetch_xor:
852 case AtomicExpr::AO__scoped_atomic_fetch_xor:
853 case AtomicExpr::AO__hip_atomic_fetch_xor:
854 case AtomicExpr::AO__opencl_atomic_fetch_xor:
855 handleFetchOp(cir::AtomicFetchKind::Xor);
856 break;
857
858 case AtomicExpr::AO__atomic_nand_fetch:
859 case AtomicExpr::AO__scoped_atomic_nand_fetch:
860 fetchFirst = false;
861 [[fallthrough]];
862 case AtomicExpr::AO__c11_atomic_fetch_nand:
863 case AtomicExpr::AO__atomic_fetch_nand:
864 case AtomicExpr::AO__scoped_atomic_fetch_nand:
865 handleFetchOp(cir::AtomicFetchKind::Nand);
866 break;
867
868 case AtomicExpr::AO__atomic_test_and_set: {
869 auto op = cir::AtomicTestAndSetOp::create(
870 builder, loc, ptr.getPointer(), order,
871 builder.getI64IntegerAttr(ptr.getAlignment().getQuantity()),
872 expr->isVolatile());
873 builder.createStore(loc, op, dest);
874 return;
875 }
876
877 case AtomicExpr::AO__atomic_clear: {
878 cir::AtomicClearOp::create(
879 builder, loc, ptr.getPointer(), order,
880 builder.getI64IntegerAttr(ptr.getAlignment().getQuantity()),
881 expr->isVolatile());
882 return;
883 }
884
885 case AtomicExpr::AO__atomic_fetch_uinc:
886 case AtomicExpr::AO__scoped_atomic_fetch_uinc:
887 handleFetchOp(cir::AtomicFetchKind::UIncWrap);
888 break;
889
890 case AtomicExpr::AO__atomic_fetch_udec:
891 case AtomicExpr::AO__scoped_atomic_fetch_udec:
892 handleFetchOp(cir::AtomicFetchKind::UDecWrap);
893 break;
894
895 case AtomicExpr::AO__opencl_atomic_init:
896 cgf.cgm.errorNYI(expr->getSourceRange(), "emitAtomicOp: expr op NYI");
897 return;
898 }
899
900 assert(!opName.empty() && "expected operation name to build");
901 mlir::Value loadVal1 = builder.createLoad(loc, val1);
902
903 SmallVector<mlir::Value> atomicOperands = {ptr.getPointer(), loadVal1};
904 SmallVector<mlir::Type> atomicResTys = {loadVal1.getType()};
905 mlir::Operation *rmwOp = builder.create(loc, builder.getStringAttr(opName),
906 atomicOperands, atomicResTys);
907
908 if (fetchAttr)
909 rmwOp->setAttr("binop", fetchAttr);
910 rmwOp->setAttr("mem_order", orderAttr);
911 rmwOp->setAttr("sync_scope", scopeAttr);
912 if (expr->isVolatile())
913 rmwOp->setAttr("is_volatile", builder.getUnitAttr());
914 if (fetchFirst && opName == cir::AtomicFetchOp::getOperationName())
915 rmwOp->setAttr("fetch_first", builder.getUnitAttr());
916
917 mlir::Value result = rmwOp->getResult(0);
918
919 builder.createStore(loc, result, dest);
920}
921
922// Map clang sync scope to CIR sync scope.
923static cir::SyncScopeKind convertSyncScopeToCIR(CIRGenFunction &cgf,
924 SourceRange range,
925 clang::SyncScope scope) {
926 switch (scope) {
928 return cir::SyncScopeKind::SingleThread;
930 return cir::SyncScopeKind::System;
932 return cir::SyncScopeKind::Device;
934 return cir::SyncScopeKind::Workgroup;
936 return cir::SyncScopeKind::Wavefront;
938 return cir::SyncScopeKind::Cluster;
939
941 return cir::SyncScopeKind::HIPSingleThread;
943 return cir::SyncScopeKind::HIPSystem;
945 return cir::SyncScopeKind::HIPAgent;
947 return cir::SyncScopeKind::HIPWorkgroup;
949 return cir::SyncScopeKind::HIPWavefront;
951 return cir::SyncScopeKind::HIPCluster;
952
954 return cir::SyncScopeKind::OpenCLWorkGroup;
956 return cir::SyncScopeKind::OpenCLDevice;
958 return cir::SyncScopeKind::OpenCLAllSVMDevices;
960 return cir::SyncScopeKind::OpenCLSubGroup;
961 }
962
963 llvm_unreachable("unhandled sync scope");
964}
965
967 Address ptr, Address val1, Address val2,
968 Expr *isWeakExpr, Expr *failureOrderExpr, int64_t size,
969 cir::MemOrder order,
970 const std::optional<Expr::EvalResult> &scopeConst,
971 mlir::Value scopeValue) {
972 std::unique_ptr<AtomicScopeModel> scopeModel = expr->getScopeModel();
973
974 if (!scopeModel) {
975 emitAtomicOp(cgf, expr, dest, ptr, val1, val2, isWeakExpr, failureOrderExpr,
976 size, order, cir::SyncScopeKind::System);
977 return;
978 }
979
980 if (scopeConst.has_value()) {
981 cir::SyncScopeKind mappedScope = convertSyncScopeToCIR(
982 cgf, expr->getScope()->getSourceRange(),
983 scopeModel->map(scopeConst->Val.getInt().getZExtValue()));
984 emitAtomicOp(cgf, expr, dest, ptr, val1, val2, isWeakExpr, failureOrderExpr,
985 size, order, mappedScope);
986 return;
987 }
988
989 // The sync scope is not a compile-time constant. Emit a switch statement to
990 // handle each possible value of the sync scope.
991 CIRGenBuilderTy &builder = cgf.getBuilder();
992 mlir::Location loc = cgf.getLoc(expr->getSourceRange());
993 llvm::ArrayRef<unsigned> allScopes = scopeModel->getRuntimeValues();
994 unsigned fallback = scopeModel->getFallBackValue();
995
996 cir::SwitchOp::create(
997 builder, loc, scopeValue,
998 [&](mlir::OpBuilder &, mlir::Location loc, mlir::OperationState &) {
999 mlir::Block *switchBlock = builder.getBlock();
1000
1001 // Default case -- use fallback scope
1002 cir::SyncScopeKind fallbackScope = convertSyncScopeToCIR(
1003 cgf, expr->getScope()->getSourceRange(), scopeModel->map(fallback));
1004 emitDefaultCaseLabel(builder, loc);
1005 emitAtomicOp(cgf, expr, dest, ptr, val1, val2, isWeakExpr,
1006 failureOrderExpr, size, order, fallbackScope);
1007 builder.createBreak(loc);
1008 builder.setInsertionPointToEnd(switchBlock);
1009
1010 // Emit a switch case for each non-fallback runtime scope value
1011 for (unsigned scope : allScopes) {
1012 if (scope == fallback)
1013 continue;
1014
1015 cir::SyncScopeKind cirScope = convertSyncScopeToCIR(
1016 cgf, expr->getScope()->getSourceRange(), scopeModel->map(scope));
1017
1018 mlir::ArrayAttr casesAttr = builder.getArrayAttr(
1019 {cir::IntAttr::get(scopeValue.getType(), scope)});
1020 mlir::OpBuilder::InsertPoint insertPoint;
1021 cir::CaseOp::create(builder, loc, casesAttr, cir::CaseOpKind::Equal,
1022 insertPoint);
1023
1024 builder.restoreInsertionPoint(insertPoint);
1025 emitAtomicOp(cgf, expr, dest, ptr, val1, val2, isWeakExpr,
1026 failureOrderExpr, size, order, cirScope);
1027 builder.createBreak(loc);
1028 builder.setInsertionPointToEnd(switchBlock);
1029 }
1030
1031 builder.createYield(loc);
1032 });
1033}
1034
1035static std::optional<cir::MemOrder>
1036getEffectiveAtomicMemOrder(cir::MemOrder oriOrder, bool isStore, bool isLoad,
1037 bool isFence) {
1038 // Some memory orders are not supported by partial atomic operation:
1039 // {memory_order_releaxed} is not valid for fence operations.
1040 // {memory_order_consume, memory_order_acquire} are not valid for write-only
1041 // operations.
1042 // {memory_order_release} is not valid for read-only operations.
1043 // {memory_order_acq_rel} is only valid for read-write operations.
1044 if (isStore) {
1045 if (oriOrder == cir::MemOrder::Consume ||
1046 oriOrder == cir::MemOrder::Acquire ||
1047 oriOrder == cir::MemOrder::AcquireRelease)
1048 return std::nullopt;
1049 } else if (isLoad) {
1050 if (oriOrder == cir::MemOrder::Release ||
1051 oriOrder == cir::MemOrder::AcquireRelease)
1052 return std::nullopt;
1053 } else if (isFence) {
1054 if (oriOrder == cir::MemOrder::Relaxed)
1055 return std::nullopt;
1056 }
1057 // memory_order_consume is not implemented, it is always treated like
1058 // memory_order_acquire
1059 if (oriOrder == cir::MemOrder::Consume)
1060 return cir::MemOrder::Acquire;
1061 return oriOrder;
1062}
1063
1065 CIRGenFunction &cgf, mlir::Value order, bool isStore, bool isLoad,
1066 bool isFence, llvm::function_ref<void(cir::MemOrder)> emitAtomicOpFn) {
1067 if (!order)
1068 return;
1069 // The memory order is not known at compile-time. The atomic operations
1070 // can't handle runtime memory orders; the memory order must be hard coded.
1071 // Generate a "switch" statement that converts a runtime value into a
1072 // compile-time value.
1073 CIRGenBuilderTy &builder = cgf.getBuilder();
1074 cir::SwitchOp::create(
1075 builder, order.getLoc(), order,
1076 [&](mlir::OpBuilder &, mlir::Location loc, mlir::OperationState &) {
1077 mlir::Block *switchBlock = builder.getBlock();
1078
1079 auto emitMemOrderCase = [&](llvm::ArrayRef<cir::MemOrder> caseOrders) {
1080 // Checking there are same effective memory order for each case.
1081 for (int i = 1, e = caseOrders.size(); i < e; i++)
1082 assert((getEffectiveAtomicMemOrder(caseOrders[i - 1], isStore,
1083 isLoad, isFence) ==
1084 getEffectiveAtomicMemOrder(caseOrders[i], isStore, isLoad,
1085 isFence)) &&
1086 "Effective memory order must be same!");
1087 // Emit case label and atomic opeartion if neccessary.
1088 if (caseOrders.empty()) {
1089 emitDefaultCaseLabel(builder, loc);
1090 // There is no good way to report an unsupported memory order at
1091 // runtime, hence the fallback to memory_order_relaxed.
1092 if (!isFence)
1093 emitAtomicOpFn(cir::MemOrder::Relaxed);
1094 } else if (std::optional<cir::MemOrder> actualOrder =
1095 getEffectiveAtomicMemOrder(caseOrders[0], isStore,
1096 isLoad, isFence)) {
1097 // Included in default case.
1098 if (!isFence && actualOrder == cir::MemOrder::Relaxed)
1099 return;
1100 // Creating case operation for effective memory order. If there are
1101 // multiple cases in `caseOrders`, the actual order of each case
1102 // must be same, this needs to be guaranteed by the caller.
1103 emitMemOrderCaseLabel(builder, loc, order.getType(), caseOrders);
1104 emitAtomicOpFn(actualOrder.value());
1105 } else {
1106 // Do nothing if (!caseOrders.empty() && !actualOrder)
1107 return;
1108 }
1109 builder.createBreak(loc);
1110 builder.setInsertionPointToEnd(switchBlock);
1111 };
1112
1113 emitMemOrderCase(/*default:*/ {});
1114 emitMemOrderCase({cir::MemOrder::Relaxed});
1115 emitMemOrderCase({cir::MemOrder::Consume, cir::MemOrder::Acquire});
1116 emitMemOrderCase({cir::MemOrder::Release});
1117 emitMemOrderCase({cir::MemOrder::AcquireRelease});
1118 emitMemOrderCase({cir::MemOrder::SequentiallyConsistent});
1119
1120 builder.createYield(loc);
1121 });
1122}
1123
1125 const Expr *memOrder, bool isStore, bool isLoad, bool isFence,
1126 llvm::function_ref<void(cir::MemOrder)> emitAtomicOpFn) {
1127 // Emit the memory order operand, and try to evaluate it as a constant.
1128 Expr::EvalResult eval;
1129 if (memOrder->EvaluateAsInt(eval, getContext())) {
1130 uint64_t constOrder = eval.Val.getInt().getZExtValue();
1131 // We should not ever get to a case where the ordering isn't a valid CABI
1132 // value, but it's hard to enforce that in general.
1133 if (!cir::isValidCIRAtomicOrderingCABI(constOrder))
1134 return;
1135 cir::MemOrder oriOrder = static_cast<cir::MemOrder>(constOrder);
1136 if (std::optional<cir::MemOrder> actualOrder =
1137 getEffectiveAtomicMemOrder(oriOrder, isStore, isLoad, isFence))
1138 emitAtomicOpFn(actualOrder.value());
1139 return;
1140 }
1141
1142 // Otherwise, handle variable memory ordering. Emit `SwitchOp` to convert
1143 // dynamic value to static value.
1144 mlir::Value dynOrder = emitScalarExpr(memOrder);
1145 emitAtomicExprWithDynamicMemOrder(*this, dynOrder, isStore, isLoad, isFence,
1146 emitAtomicOpFn);
1147}
1148
1149static RValue emitAtomicLibCall(CIRGenFunction &cgf, llvm::StringRef funcName,
1150 QualType resultType, CallArgList &args) {
1151 const CIRGenFunctionInfo &fnInfo =
1152 cgf.cgm.getTypes().arrangeBuiltinFunctionCall(resultType, args);
1153 cir::FuncType fnTy = cgf.cgm.getTypes().getFunctionType(fnInfo);
1154
1155 mlir::NamedAttrList fnAttrs;
1157
1158 cir::FuncOp fn = cgf.cgm.createRuntimeFunction(fnTy, funcName, fnAttrs);
1159 auto callee = CIRGenCallee::forDirect(fn);
1160 return cgf.emitCall(fnInfo, callee, ReturnValueSlot(), args,
1161 /*isMustTail=*/false);
1162}
1163
1165 Address atomicPtr, Address dest,
1166 Address val1, Address val2,
1167 uint64_t atomicTySize,
1168 QualType resultTy) {
1169 mlir::Location loc = cgf.getLoc(e->getSourceRange());
1170
1171 CallArgList args;
1172 // For non-optimized library calls, the size is the first parameter.
1173 args.add(
1174 RValue::get(cgf.getBuilder().getConstInt(loc, cgf.sizeTy, atomicTySize)),
1175 cgf.getContext().getSizeType());
1176
1177 // The atomic address is the second parameter.
1178 // The OpenCL atomic library functions only accept pointer arguments to
1179 // generic address space.
1180 auto castToGenericAddrSpace = [&](mlir::Value v, QualType pt) {
1181 if (!e->isOpenCL())
1182 return cgf.getBuilder().createPtrBitcast(v, cgf.voidTy);
1183
1185 cgf.cgm.errorNYI(loc, "emitLibCallForAtomicExpr: openCL");
1186 return cgf.getBuilder().createPtrBitcast(v, cgf.voidTy);
1187 };
1188 args.add(RValue::get(castToGenericAddrSpace(atomicPtr.emitRawPointer(),
1189 e->getPtr()->getType())),
1190 cgf.getContext().VoidPtrTy);
1191
1192 mlir::Value order = cgf.emitScalarExpr(e->getOrder());
1193
1194 // The next 1-3 parameters are op-dependent.
1195 llvm::StringRef calleeName;
1196 QualType retTy;
1197 bool hasRetTy = false;
1198 switch (e->getOp()) {
1199 case AtomicExpr::AO__c11_atomic_init:
1200 case AtomicExpr::AO__opencl_atomic_init:
1201 llvm_unreachable("Already handled!");
1202
1203 // There is only one libcall for compare an exchange, because there is no
1204 // optimisation benefit possible from a libcall version of a weak compare
1205 // and exchange.
1206 // bool __atomic_compare_exchange(size_t size, void *mem, void *expected,
1207 // void *desired, int success, int failure)
1208 case AtomicExpr::AO__atomic_compare_exchange:
1209 case AtomicExpr::AO__atomic_compare_exchange_n:
1210 case AtomicExpr::AO__c11_atomic_compare_exchange_weak:
1211 case AtomicExpr::AO__c11_atomic_compare_exchange_strong:
1212 case AtomicExpr::AO__hip_atomic_compare_exchange_weak:
1213 case AtomicExpr::AO__hip_atomic_compare_exchange_strong:
1214 case AtomicExpr::AO__opencl_atomic_compare_exchange_weak:
1215 case AtomicExpr::AO__opencl_atomic_compare_exchange_strong:
1216 case AtomicExpr::AO__scoped_atomic_compare_exchange:
1217 case AtomicExpr::AO__scoped_atomic_compare_exchange_n: {
1218 calleeName = "__atomic_compare_exchange";
1219 retTy = cgf.getContext().BoolTy;
1220 hasRetTy = true;
1221 mlir::Value orderFail = cgf.emitScalarExpr(e->getOrderFail());
1222 args.add(RValue::get(castToGenericAddrSpace(val1.emitRawPointer(),
1223 e->getVal1()->getType())),
1224 cgf.getContext().VoidPtrTy);
1225 args.add(RValue::get(castToGenericAddrSpace(val2.emitRawPointer(),
1226 e->getVal2()->getType())),
1227 cgf.getContext().VoidPtrTy);
1228 args.add(RValue::get(order), cgf.getContext().IntTy);
1229 order = orderFail;
1230 break;
1231 }
1232
1233 // void __atomic_exchange(size_t size, void *mem, void *val, void *return,
1234 // int order)
1235 case AtomicExpr::AO__atomic_exchange:
1236 case AtomicExpr::AO__atomic_exchange_n:
1237 case AtomicExpr::AO__c11_atomic_exchange:
1238 case AtomicExpr::AO__hip_atomic_exchange:
1239 case AtomicExpr::AO__opencl_atomic_exchange:
1240 case AtomicExpr::AO__scoped_atomic_exchange:
1241 case AtomicExpr::AO__scoped_atomic_exchange_n:
1242 calleeName = "__atomic_exchange";
1243 args.add(RValue::get(castToGenericAddrSpace(val1.emitRawPointer(),
1244 e->getVal1()->getType())),
1245 cgf.getContext().VoidPtrTy);
1246 break;
1247
1248 // void __atomic_store(size_t size, void *mem, void *val, int order)
1249 case AtomicExpr::AO__atomic_store:
1250 case AtomicExpr::AO__atomic_store_n:
1251 case AtomicExpr::AO__c11_atomic_store:
1252 case AtomicExpr::AO__hip_atomic_store:
1253 case AtomicExpr::AO__opencl_atomic_store:
1254 case AtomicExpr::AO__scoped_atomic_store:
1255 case AtomicExpr::AO__scoped_atomic_store_n:
1256 calleeName = "__atomic_store";
1257 retTy = cgf.getContext().VoidTy;
1258 hasRetTy = true;
1259 args.add(RValue::get(castToGenericAddrSpace(val1.emitRawPointer(),
1260 e->getVal1()->getType())),
1261 cgf.getContext().VoidPtrTy);
1262 break;
1263
1264 // void __atomic_load(size_t size, void *mem, void *return, int order)
1265 case AtomicExpr::AO__atomic_load:
1266 case AtomicExpr::AO__atomic_load_n:
1267 case AtomicExpr::AO__c11_atomic_load:
1268 case AtomicExpr::AO__hip_atomic_load:
1269 case AtomicExpr::AO__opencl_atomic_load:
1270 case AtomicExpr::AO__scoped_atomic_load:
1271 case AtomicExpr::AO__scoped_atomic_load_n:
1272 calleeName = "__atomic_load";
1273 break;
1274
1275 case AtomicExpr::AO__atomic_add_fetch:
1276 case AtomicExpr::AO__scoped_atomic_add_fetch:
1277 case AtomicExpr::AO__atomic_fetch_add:
1278 case AtomicExpr::AO__c11_atomic_fetch_add:
1279 case AtomicExpr::AO__hip_atomic_fetch_add:
1280 case AtomicExpr::AO__opencl_atomic_fetch_add:
1281 case AtomicExpr::AO__scoped_atomic_fetch_add:
1282 case AtomicExpr::AO__atomic_and_fetch:
1283 case AtomicExpr::AO__scoped_atomic_and_fetch:
1284 case AtomicExpr::AO__atomic_fetch_and:
1285 case AtomicExpr::AO__c11_atomic_fetch_and:
1286 case AtomicExpr::AO__hip_atomic_fetch_and:
1287 case AtomicExpr::AO__opencl_atomic_fetch_and:
1288 case AtomicExpr::AO__scoped_atomic_fetch_and:
1289 case AtomicExpr::AO__atomic_or_fetch:
1290 case AtomicExpr::AO__scoped_atomic_or_fetch:
1291 case AtomicExpr::AO__atomic_fetch_or:
1292 case AtomicExpr::AO__c11_atomic_fetch_or:
1293 case AtomicExpr::AO__hip_atomic_fetch_or:
1294 case AtomicExpr::AO__opencl_atomic_fetch_or:
1295 case AtomicExpr::AO__scoped_atomic_fetch_or:
1296 case AtomicExpr::AO__atomic_sub_fetch:
1297 case AtomicExpr::AO__scoped_atomic_sub_fetch:
1298 case AtomicExpr::AO__atomic_fetch_sub:
1299 case AtomicExpr::AO__c11_atomic_fetch_sub:
1300 case AtomicExpr::AO__hip_atomic_fetch_sub:
1301 case AtomicExpr::AO__opencl_atomic_fetch_sub:
1302 case AtomicExpr::AO__scoped_atomic_fetch_sub:
1303 case AtomicExpr::AO__atomic_xor_fetch:
1304 case AtomicExpr::AO__scoped_atomic_xor_fetch:
1305 case AtomicExpr::AO__atomic_fetch_xor:
1306 case AtomicExpr::AO__c11_atomic_fetch_xor:
1307 case AtomicExpr::AO__hip_atomic_fetch_xor:
1308 case AtomicExpr::AO__opencl_atomic_fetch_xor:
1309 case AtomicExpr::AO__scoped_atomic_fetch_xor:
1310 case AtomicExpr::AO__atomic_nand_fetch:
1311 case AtomicExpr::AO__atomic_fetch_nand:
1312 case AtomicExpr::AO__c11_atomic_fetch_nand:
1313 case AtomicExpr::AO__scoped_atomic_fetch_nand:
1314 case AtomicExpr::AO__scoped_atomic_nand_fetch:
1315 case AtomicExpr::AO__atomic_min_fetch:
1316 case AtomicExpr::AO__atomic_fetch_min:
1317 case AtomicExpr::AO__c11_atomic_fetch_min:
1318 case AtomicExpr::AO__hip_atomic_fetch_min:
1319 case AtomicExpr::AO__opencl_atomic_fetch_min:
1320 case AtomicExpr::AO__scoped_atomic_fetch_min:
1321 case AtomicExpr::AO__scoped_atomic_min_fetch:
1322 case AtomicExpr::AO__atomic_max_fetch:
1323 case AtomicExpr::AO__atomic_fetch_max:
1324 case AtomicExpr::AO__c11_atomic_fetch_max:
1325 case AtomicExpr::AO__hip_atomic_fetch_max:
1326 case AtomicExpr::AO__opencl_atomic_fetch_max:
1327 case AtomicExpr::AO__scoped_atomic_fetch_max:
1328 case AtomicExpr::AO__scoped_atomic_max_fetch:
1329 case AtomicExpr::AO__scoped_atomic_fetch_uinc:
1330 case AtomicExpr::AO__scoped_atomic_fetch_udec:
1331 case AtomicExpr::AO__atomic_fetch_fmaximum:
1332 case AtomicExpr::AO__atomic_fetch_fmaximum_num:
1333 case AtomicExpr::AO__atomic_fetch_fminimum:
1334 case AtomicExpr::AO__atomic_fetch_fminimum_num:
1335 case AtomicExpr::AO__scoped_atomic_fetch_fmaximum:
1336 case AtomicExpr::AO__scoped_atomic_fetch_fmaximum_num:
1337 case AtomicExpr::AO__scoped_atomic_fetch_fminimum:
1338 case AtomicExpr::AO__scoped_atomic_fetch_fminimum_num:
1339 case AtomicExpr::AO__atomic_test_and_set:
1340 case AtomicExpr::AO__atomic_clear:
1341 case AtomicExpr::AO__atomic_fetch_uinc:
1342 case AtomicExpr::AO__atomic_fetch_udec:
1343 llvm_unreachable("Integral atomic operations always become atomicrmw!");
1344 }
1345
1346 if (e->isOpenCL()) {
1348 cgf.cgm.errorNYI(loc, "emitLibCallForAtomicExpr: openCL");
1349 return RValue::get(nullptr);
1350 }
1351
1352 // By default, assume we return a value of the atomic type.
1353 if (!hasRetTy) {
1354 // Value is returned through parameter before the order.
1355 retTy = cgf.getContext().VoidTy;
1356 args.add(RValue::get(castToGenericAddrSpace(dest.emitRawPointer(), retTy)),
1357 cgf.getContext().VoidPtrTy);
1358 }
1359
1360 // Order is always the last parameter.
1361 args.add(RValue::get(order), cgf.getContext().IntTy);
1362 if (e->isOpenCL()) {
1364 cgf.cgm.errorNYI(loc, "emitLibCallForAtomicExpr: openCL");
1365 return RValue::get(nullptr);
1366 }
1367
1368 RValue res = emitAtomicLibCall(cgf, calleeName, retTy, args);
1369
1370 // The value is returned directly from the libcall.
1371 if (e->isCmpXChg())
1372 return res;
1373
1374 if (resultTy->isVoidType())
1375 return RValue::get(nullptr);
1376
1377 return cgf.convertTempToRValue(
1378 dest.withElementType(cgf.getBuilder(), cgf.convertTypeForMem(resultTy)),
1379 resultTy, e->getExprLoc());
1380}
1381
1383 QualType atomicTy = e->getPtr()->getType()->getPointeeType();
1384 QualType memTy = atomicTy;
1385 if (const auto *ty = atomicTy->getAs<AtomicType>())
1386 memTy = ty->getValueType();
1387
1388 Expr *isWeakExpr = nullptr;
1389 Expr *orderFailExpr = nullptr;
1390
1391 Address val1 = Address::invalid();
1392 Address val2 = Address::invalid();
1393 Address dest = Address::invalid();
1395
1397 if (e->getOp() == AtomicExpr::AO__c11_atomic_init) {
1398 LValue lvalue = makeAddrLValue(ptr, atomicTy);
1399 emitAtomicInit(e->getVal1(), lvalue);
1400 return RValue::get(nullptr);
1401 }
1402
1403 TypeInfoChars typeInfo = getContext().getTypeInfoInChars(atomicTy);
1404 uint64_t size = typeInfo.Width.getQuantity();
1405
1406 // Emit the sync scope operand, and try to evaluate it as a constant.
1407 mlir::Value scope =
1408 e->getScopeModel() ? emitScalarExpr(e->getScope()) : nullptr;
1409 std::optional<Expr::EvalResult> scopeConst;
1410 if (Expr::EvalResult eval;
1411 e->getScopeModel() && e->getScope()->EvaluateAsInt(eval, getContext()))
1412 scopeConst.emplace(std::move(eval));
1413
1414 switch (e->getOp()) {
1415 default:
1416 cgm.errorNYI(e->getSourceRange(), "atomic op NYI");
1417 return RValue::get(nullptr);
1418
1419 case AtomicExpr::AO__c11_atomic_init:
1420 llvm_unreachable("already handled above with emitAtomicInit");
1421
1422 case AtomicExpr::AO__atomic_load_n:
1423 case AtomicExpr::AO__scoped_atomic_load_n:
1424 case AtomicExpr::AO__c11_atomic_load:
1425 case AtomicExpr::AO__opencl_atomic_load:
1426 case AtomicExpr::AO__hip_atomic_load:
1427 case AtomicExpr::AO__atomic_test_and_set:
1428 case AtomicExpr::AO__atomic_clear:
1429 break;
1430
1431 case AtomicExpr::AO__atomic_load:
1432 case AtomicExpr::AO__scoped_atomic_load:
1433 dest = emitPointerWithAlignment(e->getVal1());
1434 break;
1435
1436 case AtomicExpr::AO__atomic_store:
1437 case AtomicExpr::AO__scoped_atomic_store:
1438 val1 = emitPointerWithAlignment(e->getVal1());
1439 break;
1440
1441 case AtomicExpr::AO__atomic_exchange:
1442 case AtomicExpr::AO__scoped_atomic_exchange:
1443 val1 = emitPointerWithAlignment(e->getVal1());
1444 dest = emitPointerWithAlignment(e->getVal2());
1445 break;
1446
1447 case AtomicExpr::AO__atomic_compare_exchange:
1448 case AtomicExpr::AO__atomic_compare_exchange_n:
1449 case AtomicExpr::AO__c11_atomic_compare_exchange_weak:
1450 case AtomicExpr::AO__c11_atomic_compare_exchange_strong:
1451 case AtomicExpr::AO__scoped_atomic_compare_exchange:
1452 case AtomicExpr::AO__scoped_atomic_compare_exchange_n:
1453 case AtomicExpr::AO__hip_atomic_compare_exchange_strong:
1454 case AtomicExpr::AO__hip_atomic_compare_exchange_weak:
1455 case AtomicExpr::AO__opencl_atomic_compare_exchange_strong:
1456 case AtomicExpr::AO__opencl_atomic_compare_exchange_weak:
1457 val1 = emitPointerWithAlignment(e->getVal1());
1458 if (e->getOp() == AtomicExpr::AO__atomic_compare_exchange ||
1459 e->getOp() == AtomicExpr::AO__scoped_atomic_compare_exchange)
1460 val2 = emitPointerWithAlignment(e->getVal2());
1461 else
1462 val2 = emitValToTemp(*this, e->getVal2());
1463 orderFailExpr = e->getOrderFail();
1464 if (e->getOp() == AtomicExpr::AO__atomic_compare_exchange_n ||
1465 e->getOp() == AtomicExpr::AO__atomic_compare_exchange ||
1466 e->getOp() == AtomicExpr::AO__scoped_atomic_compare_exchange_n ||
1467 e->getOp() == AtomicExpr::AO__scoped_atomic_compare_exchange)
1468 isWeakExpr = e->getWeak();
1469 break;
1470
1471 case AtomicExpr::AO__c11_atomic_fetch_add:
1472 case AtomicExpr::AO__c11_atomic_fetch_sub:
1473 if (memTy->isPointerType()) {
1474 // For pointer arithmetic, we're required to do a bit of math:
1475 // adding 1 to an int* is not the same as adding 1 to a uintptr_t.
1476 // ... but only for the C11 builtins. The GNU builtins expect the
1477 // user to multiply by sizeof(T).
1478 QualType val1Ty = e->getVal1()->getType();
1479 mlir::Location loc = getLoc(e->getSourceRange());
1480 mlir::Value val1Scalar = emitScalarExpr(e->getVal1());
1481 CharUnits pointeeIncAmt =
1482 getContext().getTypeSizeInChars(memTy->getPointeeType());
1483 mlir::Value scale = builder.getConstInt(loc, val1Scalar.getType(),
1484 pointeeIncAmt.getQuantity());
1485 val1Scalar = builder.createMul(loc, val1Scalar, scale);
1486 val1 = createMemTemp(val1Ty, loc, ".atomictmp");
1487 emitStoreOfScalar(val1Scalar, makeAddrLValue(val1, val1Ty),
1488 /*isInit=*/true);
1489 }
1490 [[fallthrough]];
1491 case AtomicExpr::AO__atomic_fetch_add:
1492 case AtomicExpr::AO__atomic_fetch_sub:
1493 case AtomicExpr::AO__atomic_add_fetch:
1494 case AtomicExpr::AO__atomic_sub_fetch:
1495 if (memTy->isPointerType()) {
1496 // Fetch-and-update atomic operation on pointers should treat the pointer
1497 // value as uintptr_t values
1498 if (!val1.isValid())
1499 val1 = emitValToTemp(*this, e->getVal1());
1500 ptr = ptr.withElementType(builder, val1.getElementType());
1501 break;
1502 }
1503 [[fallthrough]];
1504 case AtomicExpr::AO__atomic_fetch_max:
1505 case AtomicExpr::AO__atomic_fetch_min:
1506 case AtomicExpr::AO__atomic_max_fetch:
1507 case AtomicExpr::AO__atomic_min_fetch:
1508 case AtomicExpr::AO__c11_atomic_fetch_max:
1509 case AtomicExpr::AO__c11_atomic_fetch_min:
1510 case AtomicExpr::AO__scoped_atomic_fetch_add:
1511 case AtomicExpr::AO__scoped_atomic_fetch_max:
1512 case AtomicExpr::AO__scoped_atomic_fetch_min:
1513 case AtomicExpr::AO__scoped_atomic_fetch_sub:
1514 case AtomicExpr::AO__scoped_atomic_fetch_fminimum:
1515 case AtomicExpr::AO__scoped_atomic_fetch_fmaximum:
1516 case AtomicExpr::AO__scoped_atomic_fetch_fminimum_num:
1517 case AtomicExpr::AO__scoped_atomic_fetch_fmaximum_num:
1518 case AtomicExpr::AO__scoped_atomic_add_fetch:
1519 case AtomicExpr::AO__scoped_atomic_max_fetch:
1520 case AtomicExpr::AO__scoped_atomic_min_fetch:
1521 case AtomicExpr::AO__scoped_atomic_sub_fetch:
1522 [[fallthrough]];
1523
1524 case AtomicExpr::AO__atomic_fetch_and:
1525 case AtomicExpr::AO__atomic_fetch_nand:
1526 case AtomicExpr::AO__atomic_fetch_or:
1527 case AtomicExpr::AO__atomic_fetch_xor:
1528 case AtomicExpr::AO__atomic_and_fetch:
1529 case AtomicExpr::AO__atomic_nand_fetch:
1530 case AtomicExpr::AO__atomic_or_fetch:
1531 case AtomicExpr::AO__atomic_xor_fetch:
1532 case AtomicExpr::AO__atomic_exchange_n:
1533 case AtomicExpr::AO__atomic_store_n:
1534 case AtomicExpr::AO__c11_atomic_fetch_and:
1535 case AtomicExpr::AO__c11_atomic_fetch_nand:
1536 case AtomicExpr::AO__c11_atomic_fetch_or:
1537 case AtomicExpr::AO__c11_atomic_fetch_xor:
1538 case AtomicExpr::AO__c11_atomic_exchange:
1539 case AtomicExpr::AO__c11_atomic_store:
1540 case AtomicExpr::AO__scoped_atomic_fetch_and:
1541 case AtomicExpr::AO__scoped_atomic_fetch_nand:
1542 case AtomicExpr::AO__scoped_atomic_fetch_or:
1543 case AtomicExpr::AO__scoped_atomic_fetch_xor:
1544 case AtomicExpr::AO__scoped_atomic_and_fetch:
1545 case AtomicExpr::AO__scoped_atomic_nand_fetch:
1546 case AtomicExpr::AO__scoped_atomic_or_fetch:
1547 case AtomicExpr::AO__scoped_atomic_xor_fetch:
1548 case AtomicExpr::AO__scoped_atomic_store_n:
1549 case AtomicExpr::AO__scoped_atomic_exchange_n:
1550 case AtomicExpr::AO__atomic_fetch_uinc:
1551 case AtomicExpr::AO__atomic_fetch_udec:
1552 case AtomicExpr::AO__scoped_atomic_fetch_uinc:
1553 case AtomicExpr::AO__scoped_atomic_fetch_udec:
1554 case AtomicExpr::AO__atomic_fetch_fminimum:
1555 case AtomicExpr::AO__atomic_fetch_fmaximum:
1556 case AtomicExpr::AO__atomic_fetch_fminimum_num:
1557 case AtomicExpr::AO__atomic_fetch_fmaximum_num:
1558 case AtomicExpr::AO__hip_atomic_exchange:
1559 case AtomicExpr::AO__hip_atomic_store:
1560 case AtomicExpr::AO__hip_atomic_fetch_add:
1561 case AtomicExpr::AO__hip_atomic_fetch_sub:
1562 case AtomicExpr::AO__hip_atomic_fetch_min:
1563 case AtomicExpr::AO__hip_atomic_fetch_max:
1564 case AtomicExpr::AO__hip_atomic_fetch_and:
1565 case AtomicExpr::AO__hip_atomic_fetch_or:
1566 case AtomicExpr::AO__hip_atomic_fetch_xor:
1567 case AtomicExpr::AO__opencl_atomic_exchange:
1568 case AtomicExpr::AO__opencl_atomic_store:
1569 case AtomicExpr::AO__opencl_atomic_fetch_add:
1570 case AtomicExpr::AO__opencl_atomic_fetch_sub:
1571 case AtomicExpr::AO__opencl_atomic_fetch_min:
1572 case AtomicExpr::AO__opencl_atomic_fetch_max:
1573 case AtomicExpr::AO__opencl_atomic_fetch_and:
1574 case AtomicExpr::AO__opencl_atomic_fetch_or:
1575 case AtomicExpr::AO__opencl_atomic_fetch_xor:
1576 val1 = emitValToTemp(*this, e->getVal1());
1577 break;
1578 }
1579
1580 QualType resultTy = e->getType().getUnqualifiedType();
1581
1582 bool shouldCastToIntPtrTy =
1584
1585 // The inlined atomics only function on iN types, where N is a power of 2. We
1586 // need to make sure (via temporaries if necessary) that all incoming values
1587 // are compatible.
1588 mlir::Location loc = getLoc(e->getSourceRange());
1589 LValue atomicValue = makeAddrLValue(ptr, atomicTy);
1590 AtomicInfo atomics(*this, atomicValue, loc);
1591
1592 if (shouldCastToIntPtrTy) {
1593 ptr = atomics.castToAtomicIntPointer(ptr);
1594 if (val1.isValid())
1595 val1 = atomics.convertToAtomicIntPointer(val1, loc);
1596 if (val2.isValid())
1597 val2 = atomics.convertToAtomicIntPointer(val2, loc);
1598 }
1599 if (dest.isValid()) {
1600 if (shouldCastToIntPtrTy)
1601 dest = atomics.castToAtomicIntPointer(dest);
1602 } else if (e->isCmpXChg()) {
1603 dest = createMemTemp(resultTy, loc, "cmpxchg.bool");
1604 } else if (e->getOp() == AtomicExpr::AO__atomic_test_and_set) {
1605 dest = createMemTemp(resultTy, loc, "test_and_set.bool");
1606 } else if (!resultTy->isVoidType()) {
1607 dest = atomics.createTempAlloca();
1608 if (shouldCastToIntPtrTy)
1609 dest = atomics.castToAtomicIntPointer(dest);
1610 }
1611
1612 bool powerOf2Size = (size & (size - 1)) == 0;
1613 bool useLibCall = !powerOf2Size || (size > 16);
1614
1615 // For atomics larger than 16 bytes, emit a libcall from the frontend. This
1616 // avoids the overhead of dealing with excessively-large value types in IR.
1617 // Non-power-of-2 values also lower to libcall here, as they are not currently
1618 // permitted in IR instructions (although that constraint could be relaxed in
1619 // the future). For other cases where a libcall is required on a given
1620 // platform, we let the backend handle it (this includes handling for all of
1621 // the size-optimized libcall variants, which are only valid up to 16 bytes.)
1622 //
1623 // See: https://llvm.org/docs/Atomics.html#libcalls-atomic
1624 if (useLibCall)
1625 return emitLibCallForAtomicExpr(*this, e, ptr, dest, val1, val2, size,
1626 resultTy);
1627
1628 bool isStore = e->getOp() == AtomicExpr::AO__c11_atomic_store ||
1629 e->getOp() == AtomicExpr::AO__opencl_atomic_store ||
1630 e->getOp() == AtomicExpr::AO__hip_atomic_store ||
1631 e->getOp() == AtomicExpr::AO__atomic_store ||
1632 e->getOp() == AtomicExpr::AO__atomic_store_n ||
1633 e->getOp() == AtomicExpr::AO__scoped_atomic_store ||
1634 e->getOp() == AtomicExpr::AO__scoped_atomic_store_n ||
1635 e->getOp() == AtomicExpr::AO__atomic_clear;
1636 bool isLoad = e->getOp() == AtomicExpr::AO__c11_atomic_load ||
1637 e->getOp() == AtomicExpr::AO__opencl_atomic_load ||
1638 e->getOp() == AtomicExpr::AO__hip_atomic_load ||
1639 e->getOp() == AtomicExpr::AO__atomic_load ||
1640 e->getOp() == AtomicExpr::AO__atomic_load_n ||
1641 e->getOp() == AtomicExpr::AO__scoped_atomic_load ||
1642 e->getOp() == AtomicExpr::AO__scoped_atomic_load_n;
1643
1644 auto emitAtomicOpCallBackFn = [&](cir::MemOrder memOrder) {
1645 emitAtomicOp(*this, e, dest, ptr, val1, val2, isWeakExpr, orderFailExpr,
1646 size, memOrder, scopeConst, scope);
1647 };
1648 emitAtomicExprWithMemOrder(e->getOrder(), isStore, isLoad, /*isFence*/ false,
1649 emitAtomicOpCallBackFn);
1650
1651 if (resultTy->isVoidType())
1652 return RValue::get(nullptr);
1653
1654 return convertTempToRValue(
1655 dest.withElementType(builder, convertTypeForMem(resultTy)), resultTy,
1656 e->getExprLoc());
1657}
1658
1660 AggValueSlot slot) {
1661 if (lvalue.getType()->isAtomicType())
1662 return emitAtomicLoad(lvalue, loc, cir::MemOrder::SequentiallyConsistent,
1663 /*isVolatile=*/lvalue.isVolatileQualified(), slot);
1664 return emitAtomicLoad(lvalue, loc, cir::MemOrder::Acquire,
1665 /*isVolatile=*/true, slot);
1666}
1667
1669 cir::MemOrder order, bool isVolatile,
1670 AggValueSlot slot) {
1671 AtomicInfo info(*this, lvalue, getLoc(loc));
1672 return info.emitAtomicLoad(slot, loc, /*asValue=*/true, order, isVolatile);
1673}
1674
1675void CIRGenFunction::emitAtomicStore(RValue rvalue, LValue dest, bool isInit) {
1676 bool isVolatile = dest.isVolatileQualified();
1677 auto order = cir::MemOrder::SequentiallyConsistent;
1678 if (!dest.getType()->isAtomicType()) {
1680 }
1681 return emitAtomicStore(rvalue, dest, order, isVolatile, isInit);
1682}
1683
1684/// Emit a store to an l-value of atomic type.
1685///
1686/// Note that the r-value is expected to be an r-value of the atomic type; this
1687/// means that for aggregate r-values, it should include storage for any padding
1688/// that was necessary.
1690 cir::MemOrder order, bool isVolatile,
1691 bool isInit) {
1692 // If this is an aggregate r-value, it should agree in type except
1693 // maybe for address-space qualification.
1694 mlir::Location loc = dest.getPointer().getLoc();
1695 assert(!rvalue.isAggregate() ||
1697 dest.getAddress().getElementType());
1698
1699 AtomicInfo atomics(*this, dest, loc);
1700 LValue lvalue = atomics.getAtomicLValue();
1701
1702 if (lvalue.isSimple()) {
1703 // If this is an initialization, just put the value there normally.
1704 if (isInit) {
1705 atomics.emitCopyIntoMemory(rvalue);
1706 return;
1707 }
1708
1709 // Check whether we should use a library call.
1710 if (atomics.shouldUseLibCall()) {
1712 cgm.errorNYI(loc, "emitAtomicStore: atomic store with library call");
1713 return;
1714 }
1715
1716 // Okay, we're doing this natively.
1717 mlir::Value valueToStore = atomics.convertRValueToInt(rvalue, loc);
1718
1719 // Do the atomic store.
1720 Address addr = atomics.getAtomicAddress();
1721 if (mlir::Value value = atomics.getScalarRValValueOrNull(rvalue)) {
1722 if (shouldCastToInt(value.getType(), /*CmpXchg=*/false)) {
1723 addr = atomics.castToAtomicIntPointer(addr);
1724 valueToStore =
1725 builder.createIntCast(valueToStore, addr.getElementType());
1726 }
1727 }
1728 cir::StoreOp store = builder.createStore(loc, valueToStore, addr);
1729
1730 // Initializations don't need to be atomic.
1731 if (!isInit) {
1733 store.setMemOrder(order);
1734 }
1735
1736 // Other decoration.
1737 if (isVolatile)
1738 store.setIsVolatile(true);
1739
1741 return;
1742 }
1743
1744 cgm.errorNYI(loc, "emitAtomicStore: non-simple atomic lvalue");
1746}
1747
1749 AtomicInfo atomics(*this, dest, getLoc(init->getSourceRange()));
1750
1751 switch (atomics.getEvaluationKind()) {
1752 case cir::TEK_Scalar: {
1753 mlir::Value value = emitScalarExpr(init);
1754 atomics.emitCopyIntoMemory(RValue::get(value));
1755 return;
1756 }
1757
1758 case cir::TEK_Complex: {
1759 mlir::Value value = emitComplexExpr(init);
1760 atomics.emitCopyIntoMemory(RValue::get(value));
1761 return;
1762 }
1763
1764 case cir::TEK_Aggregate: {
1765 // Fix up the destination if the initializer isn't an expression
1766 // of atomic type.
1767 bool zeroed = false;
1768 if (!init->getType()->isAtomicType()) {
1769 zeroed = atomics.emitMemSetZeroIfNecessary();
1770 dest = atomics.projectValue();
1771 }
1772
1773 // Evaluate the expression directly into the destination.
1779
1780 emitAggExpr(init, slot);
1781 return;
1782 }
1783 }
1784
1785 llvm_unreachable("bad evaluation kind");
1786}
static bool shouldCastToInt(mlir::Type valueTy, bool cmpxchg)
Return true if.
static Address emitValToTemp(CIRGenFunction &cgf, Expr *e)
static void emitAtomicCmpXchgFailureSetCheckWeak(CIRGenFunction &cgf, AtomicExpr *e, Expr *isWeakExpr, Address dest, Address ptr, Address val1, Address val2, Expr *failureOrderExpr, uint64_t size, cir::MemOrder successOrder, cir::SyncScopeKind scope)
static void emitAtomicCmpXchg(CIRGenFunction &cgf, AtomicExpr *e, bool isWeak, Address dest, Address ptr, Address val1, Address val2, uint64_t size, cir::MemOrder successOrder, cir::MemOrder failureOrder, cir::SyncScopeKind scope)
static void emitMemOrderCaseLabel(CIRGenBuilderTy &builder, mlir::Location loc, mlir::Type orderType, llvm::ArrayRef< cir::MemOrder > orders)
static cir::SyncScopeKind convertSyncScopeToCIR(CIRGenFunction &cgf, SourceRange range, clang::SyncScope scope)
static RValue emitLibCallForAtomicExpr(CIRGenFunction &cgf, AtomicExpr *e, Address atomicPtr, Address dest, Address val1, Address val2, uint64_t atomicTySize, QualType resultTy)
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)
static RValue emitAtomicLibCall(CIRGenFunction &cgf, llvm::StringRef funcName, QualType resultType, CallArgList &args)
*collection of selector each with an associated kind and an ordered *collection of selectors A selector has a kind
cir::BreakOp createBreak(mlir::Location loc)
Create a break operation.
mlir::Value createPtrBitcast(mlir::Value src, mlir::Type newPointeeTy)
mlir::Value createNot(mlir::Location loc, mlir::Value value)
cir::YieldOp createYield(mlir::Location loc, mlir::ValueRange value={})
Create a yield operation.
cir::BoolType getBoolTy()
llvm::TypeSize getTypeSizeInBits(mlir::Type ty) const
llvm::TypeSize getTypeStoreSize(mlir::Type ty) const
Returns the maximum number of bytes that may be overwritten by storing the specified type.
APSInt & getInt()
Definition APValue.h:512
CanQualType VoidPtrTy
CanQualType BoolTy
TypeInfo getTypeInfo(const Type *T) const
Get the size and alignment of the specified complete type in bits.
CanQualType IntTy
int64_t toBits(CharUnits CharSize) const
Convert a size in characters to a size in bits.
CanQualType VoidTy
QualType getSizeType() const
Return the unique type for "size_t" (C99 7.17), defined in <stddef.h>.
const TargetInfo & getTargetInfo() const
Definition ASTContext.h:965
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,...
Definition Expr.h:6978
static std::unique_ptr< AtomicScopeModel > getScopeModel(AtomicOp Op)
Get atomic scope model for the atomic op code.
Definition Expr.h:7127
Expr * getVal2() const
Definition Expr.h:7029
Expr * getOrder() const
Definition Expr.h:7012
Expr * getScope() const
Definition Expr.h:7015
bool isCmpXChg() const
Definition Expr.h:7062
AtomicOp getOp() const
Definition Expr.h:7041
bool isOpenCL() const
Definition Expr.h:7090
Expr * getVal1() const
Definition Expr.h:7019
Expr * getPtr() const
Definition Expr.h:7009
Expr * getWeak() const
Definition Expr.h:7035
Expr * getOrderFail() const
Definition Expr.h:7025
bool isVolatile() const
Definition Expr.h:7058
Address withPointer(mlir::Value newPtr) const
Return address with different pointer, but same element type and alignment.
Definition Address.h:83
mlir::Value getPointer() const
Definition Address.h:98
mlir::Type getElementType() const
Definition Address.h:125
static Address invalid()
Definition Address.h:76
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
Definition Address.h:138
bool isValid() const
Definition Address.h:77
mlir::Value emitRawPointer() const
Return the pointer contained in this class after authenticating it and adding offset to it if necessa...
Definition Address.h:112
An aggregate value slot.
static AggValueSlot forLValue(const LValue &LV, IsDestructed_t isDestructed, IsAliased_t isAliased, Overlap_t mayOverlap, IsZeroed_t isZeroed=IsNotZeroed)
cir::LoadOp createLoad(mlir::Location loc, Address addr, bool isVolatile=false, bool isNontemporal=false)
cir::StoreOp createStore(mlir::Location loc, mlir::Value val, Address dst, bool isVolatile=false, bool isNontemporal=false, mlir::IntegerAttr align={}, cir::SyncScopeKindAttr scope={}, cir::MemOrderAttr order={})
cir::MemCpyOp createMemCpy(mlir::Location loc, Address dst, Address src, mlir::Value len)
cir::ConstantOp getConstInt(mlir::Location loc, llvm::APSInt intVal)
cir::MemSetOp createMemSet(mlir::Location loc, mlir::Value dst, mlir::Value val, mlir::Value len)
cir::IntType getUIntNTy(int n)
static CIRGenCallee forDirect(mlir::Operation *funcPtr, const CIRGenCalleeInfo &abstractInfo=CIRGenCalleeInfo())
Definition CIRGenCall.h:92
RValue convertTempToRValue(Address addr, clang::QualType type, clang::SourceLocation loc)
Given the address of a temporary variable, produce an r-value of its type.
Address emitPointerWithAlignment(const clang::Expr *expr, LValueBaseInfo *baseInfo=nullptr)
Given an expression with a pointer type, emit the value and compute our best estimate of the alignmen...
mlir::Value emitComplexExpr(const Expr *e)
Emit the computation of the specified expression of complex type, returning the result.
mlir::Location getLoc(clang::SourceLocation srcLoc)
Helpers to convert Clang's SourceLocation to a MLIR Location.
void emitAnyExprToMem(const Expr *e, Address location, Qualifiers quals, bool isInitializer)
Emits the code necessary to evaluate an arbitrary expression into the given memory location.
RValue emitAtomicExpr(AtomicExpr *e)
RValue emitAtomicLoad(LValue lvalue, SourceLocation loc, AggValueSlot slot=AggValueSlot::ignored())
mlir::Type convertTypeForMem(QualType t)
void emitStoreOfScalar(mlir::Value value, Address addr, bool isVolatile, clang::QualType ty, LValueBaseInfo baseInfo, bool isInit=false, bool isNontemporal=false)
void emitStoreOfComplex(mlir::Location loc, mlir::Value v, LValue dest, bool isInit)
EmitStoreOfComplex - Store a complex number into the specified l-value.
void emitAtomicExprWithMemOrder(const Expr *memOrder, bool isStore, bool isLoad, bool isFence, llvm::function_ref< void(cir::MemOrder)> emitAtomicOp)
mlir::Value emitToMemory(mlir::Value value, clang::QualType ty)
Given a value and its clang type, returns the value casted to its memory representation.
mlir::Value emitScalarExpr(const clang::Expr *e, bool ignoreResultAssign=false)
Emit the computation of the specified expression of scalar type.
CIRGenBuilderTy & getBuilder()
mlir::MLIRContext & getMLIRContext()
void emitAtomicInit(Expr *init, LValue dest)
RValue emitCall(const CIRGenFunctionInfo &funcInfo, const CIRGenCallee &callee, ReturnValueSlot returnValue, const CallArgList &args, cir::CIRCallOpInterface *callOp, bool isMustTail, SourceRange clangLoc)
LValue makeAddrLValue(Address addr, QualType ty, AlignmentSource source=AlignmentSource::Type)
void emitAtomicStore(RValue rvalue, LValue dest, bool isInit)
clang::ASTContext & getContext() const
mlir::Value emitFromMemory(mlir::Value value, clang::QualType ty)
EmitFromMemory - Change a scalar value from its memory representation to its value representation.
Address createMemTemp(QualType t, mlir::Location loc, const Twine &name="tmp", Address *alloca=nullptr, mlir::OpBuilder::InsertPoint ip={})
Create a temporary memory object of the given type, with appropriate alignmen and cast it to the defa...
void emitAggExpr(const clang::Expr *e, AggValueSlot slot)
This class organizes the cross-function state that is used while generating CIR code.
DiagnosticBuilder errorNYI(SourceLocation, llvm::StringRef)
Helpers to emit "not yet implemented" error diagnostics.
cir::FuncOp createRuntimeFunction(cir::FuncType ty, llvm::StringRef name, mlir::NamedAttrList extraAttrs={}, bool isLocal=false, bool assumeConvergent=false)
const cir::CIRDataLayout getDataLayout() const
const CIRGenFunctionInfo & arrangeBuiltinFunctionCall(QualType resultType, const CallArgList &args)
A builtin function is a freestanding function using the default C conventions.
cir::FuncType getFunctionType(const CIRGenFunctionInfo &info)
Get the CIR function type for.
void add(RValue rvalue, clang::QualType type)
Definition CIRGenCall.h:239
Address getAddress() const
clang::QualType getType() const
mlir::Value getPointer() const
bool isVolatileQualified() const
bool isSimple() const
This trivial value class is used to represent the result of an expression that is evaluated.
Definition CIRGenValue.h:33
Address getAggregateAddress() const
Return the value of the address of the aggregate.
Definition CIRGenValue.h:69
bool isAggregate() const
Definition CIRGenValue.h:51
static RValue get(mlir::Value v)
Definition CIRGenValue.h:83
static RValue getAggregate(Address addr, bool isVolatile=false)
Convert an Address to an RValue.
mlir::Value getValue() const
Return the value of this scalar value.
Definition CIRGenValue.h:57
bool isScalar() const
Definition CIRGenValue.h:49
mlir::Value getComplexValue() const
Return the value of this complex value.
Definition CIRGenValue.h:63
Contains the address where the return value of a function can be stored, and whether the address is v...
Definition CIRGenCall.h:260
CharUnits - This is an opaque type for sizes expressed in character units.
Definition CharUnits.h:38
llvm::Align getAsAlign() const
getAsAlign - Returns Quantity as a valid llvm::Align, Beware llvm::Align assumes power of two 8-bit b...
Definition CharUnits.h:189
QuantityType getQuantity() const
getQuantity - Get the raw integer representation of this quantity.
Definition CharUnits.h:185
This represents one expression.
Definition Expr.h:113
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...
Definition Expr.cpp:283
QualType getType() const
Definition Expr.h:145
A (possibly-)qualified type.
Definition TypeBase.h:938
Qualifiers getQualifiers() const
Retrieve the set of qualifiers applied to this type.
Definition TypeBase.h:8468
QualType getUnqualifiedType() const
Retrieve the unqualified variant of the given type, removing as little sugar as possible.
Definition TypeBase.h:8522
Encodes a location in the source.
A trivial tuple used to represent a source range.
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
Definition Stmt.cpp:343
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...
Definition TargetInfo.h:858
bool isVoidType() const
Definition TypeBase.h:9037
bool isPointerType() const
Definition TypeBase.h:8665
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
Definition Type.cpp:881
bool isAtomicType() const
Definition TypeBase.h:8857
const T * getAs() const
Member-template getAs<specific type>'.
Definition TypeBase.h:9264
bool isValidCIRAtomicOrderingCABI(Int value)
const internal::VariadicDynCastAllOfMatcher< Stmt, Expr > expr
Matches expressions.
@ Address
A pointer to a ValueDecl.
Definition Primitives.h:28
Top level wrappers for InstallAPI frontend operations.
bool isa(CodeGen::Address addr)
Definition Address.h:330
SyncScope
Defines sync scope values used internally by clang.
Definition SyncScope.h:43
unsigned long uint64_t
static bool atomicInfoGetAtomicPointer()
static bool aggValueSlotGC()
static bool opLoadStoreAtomic()
static bool opLoadStoreTbaa()
static bool opFuncExtraAttrs()
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.
Definition Expr.h:666
APValue Val
Val - This is the value the expression can be folded to.
Definition Expr.h:668