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