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