clang 23.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 CharUnits getAtomicAlignment() const { return atomicAlign; }
72 TypeEvaluationKind getEvaluationKind() const { return evaluationKind; }
73 mlir::Value getAtomicPointer() const {
74 if (lvalue.isSimple())
75 return lvalue.getPointer();
77 return nullptr;
78 }
79 bool shouldUseLibCall() const { return useLibCall; }
80 const LValue &getAtomicLValue() const { return lvalue; }
81 Address getAtomicAddress() const {
82 mlir::Type elemTy;
83 if (lvalue.isSimple()) {
84 elemTy = lvalue.getAddress().getElementType();
85 } else {
87 cgf.cgm.errorNYI(loc, "AtomicInfo::getAtomicAddress: non-simple lvalue");
88 }
89 return Address(getAtomicPointer(), elemTy, getAtomicAlignment());
90 }
91
92 /// Is the atomic size larger than the underlying value type?
93 ///
94 /// Note that the absence of padding does not mean that atomic
95 /// objects are completely interchangeable with non-atomic
96 /// objects: we might have promoted the alignment of a type
97 /// without making it bigger.
98 bool hasPadding() const { return (valueSizeInBits != atomicSizeInBits); }
99
100 bool emitMemSetZeroIfNecessary() const;
101
102 mlir::Value getScalarRValValueOrNull(RValue rvalue) const;
103
104 /// Cast the given pointer to an integer pointer suitable for atomic
105 /// operations on the source.
106 Address castToAtomicIntPointer(Address addr) const;
107
108 /// If addr is compatible with the iN that will be used for an atomic
109 /// operation, bitcast it. Otherwise, create a temporary that is suitable and
110 /// copy the value across.
111 Address convertToAtomicIntPointer(Address addr) const;
112
113 /// Converts a rvalue to integer value.
114 mlir::Value convertRValueToInt(RValue rvalue, bool cmpxchg = false) const;
115
116 RValue convertToValueOrAtomic(mlir::Value intVal, AggValueSlot resultSlot,
117 SourceLocation loc, bool asValue,
118 bool cmpxchg = false) const;
119
120 /// Copy an atomic r-value into atomic-layout memory.
121 void emitCopyIntoMemory(RValue rvalue) const;
122
123 /// Project an l-value down to the value field.
124 LValue projectValue() const {
125 assert(lvalue.isSimple());
126 Address addr = getAtomicAddress();
127 if (hasPadding()) {
128 cgf.cgm.errorNYI(loc, "AtomicInfo::projectValue: padding");
129 }
130
132 return LValue::makeAddr(addr, getValueType(), lvalue.getBaseInfo());
133 }
134
135 /// Emits atomic load.
136 /// \returns Loaded value.
137 RValue emitAtomicLoad(AggValueSlot resultSlot, SourceLocation loc,
138 bool asValue, cir::MemOrder order, bool isVolatile);
139
140 /// Creates temp alloca for intermediate operations on atomic value.
141 Address createTempAlloca() const;
142
143private:
144 bool requiresMemSetZero(mlir::Type ty) const;
145
146 /// Emits atomic load as a CIR operation.
147 mlir::Value emitAtomicLoadOp(cir::MemOrder order, bool isVolatile,
148 bool cmpxchg = false);
149};
150} // namespace
151
152// This function emits any expression (scalar, complex, or aggregate)
153// into a temporary alloca.
155 Address declPtr = cgf.createMemTemp(
156 e->getType(), cgf.getLoc(e->getSourceRange()), ".atomictmp");
157 cgf.emitAnyExprToMem(e, declPtr, e->getType().getQualifiers(),
158 /*Init*/ true);
159 return declPtr;
160}
161
162/// Does a store of the given IR type modify the full expected width?
163static bool isFullSizeType(CIRGenModule &cgm, mlir::Type ty,
164 uint64_t expectedSize) {
165 return cgm.getDataLayout().getTypeStoreSize(ty) * 8 == expectedSize;
166}
167
168/// Does the atomic type require memsetting to zero before initialization?
169///
170/// The IR type is provided as a way of making certain queries faster.
171bool AtomicInfo::requiresMemSetZero(mlir::Type ty) const {
172 // If the atomic type has size padding, we definitely need a memset.
173 if (hasPadding())
174 return true;
175
176 // Otherwise, do some simple heuristics to try to avoid it:
177 switch (getEvaluationKind()) {
178 // For scalars and complexes, check whether the store size of the
179 // type uses the full size.
180 case cir::TEK_Scalar:
181 return !isFullSizeType(cgf.cgm, ty, atomicSizeInBits);
182 case cir::TEK_Complex:
183 return !isFullSizeType(cgf.cgm,
184 mlir::cast<cir::ComplexType>(ty).getElementType(),
185 atomicSizeInBits / 2);
186 // Padding in structs has an undefined bit pattern. User beware.
188 return false;
189 }
190 llvm_unreachable("bad evaluation kind");
191}
192
193Address AtomicInfo::convertToAtomicIntPointer(Address addr) const {
194 mlir::Type ty = addr.getElementType();
195 uint64_t sourceSizeInBits = cgf.cgm.getDataLayout().getTypeSizeInBits(ty);
196 if (sourceSizeInBits != atomicSizeInBits) {
197 cgf.cgm.errorNYI(
198 loc,
199 "AtomicInfo::convertToAtomicIntPointer: convert through temp alloca");
200 }
201
202 return castToAtomicIntPointer(addr);
203}
204
205RValue AtomicInfo::emitAtomicLoad(AggValueSlot resultSlot, SourceLocation loc,
206 bool asValue, cir::MemOrder order,
207 bool isVolatile) {
208 // Check whether we should use a library call.
209 if (shouldUseLibCall()) {
211 cgf.cgm.errorNYI(loc, "emitAtomicLoad: emit atomic lib call");
212 return RValue::get(nullptr);
213 }
214
215 // Okay, we're doing this natively.
216 mlir::Value loadOp = emitAtomicLoadOp(order, isVolatile);
217
218 // If we're ignoring an aggregate return, don't do anything.
219 if (getEvaluationKind() == TEK_Aggregate && resultSlot.isIgnored())
220 return RValue::getAggregate(Address::invalid(), false);
221
222 // Okay, turn that back into the original value or atomic (for non-simple
223 // lvalues) type.
224 return convertToValueOrAtomic(loadOp, resultSlot, loc, asValue);
225}
226
227Address AtomicInfo::createTempAlloca() const {
228 // Remove addrspace info from the atomic pointer element when making the
229 // alloca pointer element.
230 QualType tmpTy = (lvalue.isBitField() && valueSizeInBits > atomicSizeInBits)
231 ? valueTy
232 : atomicTy.getUnqualifiedType();
233 Address tempAlloca =
234 cgf.createMemTemp(tmpTy, getAtomicAlignment(), loc, "atomic-temp");
235
236 // Cast to pointer to value type for bitfields.
237 if (lvalue.isBitField()) {
238 cgf.cgm.errorNYI(loc, "AtomicInfo::createTempAlloca: bitfield lvalue");
239 }
240
241 return tempAlloca;
242}
243
244mlir::Value AtomicInfo::getScalarRValValueOrNull(RValue rvalue) const {
245 if (rvalue.isScalar() && (!hasPadding() || !lvalue.isSimple()))
246 return rvalue.getValue();
247 return nullptr;
248}
249
250Address AtomicInfo::castToAtomicIntPointer(Address addr) const {
251 auto intTy = mlir::dyn_cast<cir::IntType>(addr.getElementType());
252 // Don't bother with int casts if the integer size is the same.
253 if (intTy && intTy.getWidth() == atomicSizeInBits)
254 return addr;
255 auto ty = cgf.getBuilder().getUIntNTy(atomicSizeInBits);
256 return addr.withElementType(cgf.getBuilder(), ty);
257}
258
259bool AtomicInfo::emitMemSetZeroIfNecessary() const {
260 assert(lvalue.isSimple());
261 Address addr = lvalue.getAddress();
262 if (!requiresMemSetZero(addr.getElementType()))
263 return false;
264
265 cgf.cgm.errorNYI(loc,
266 "AtomicInfo::emitMemSetZeroIfNecaessary: emit memset zero");
267 return false;
268}
269
270/// Return true if \param valueTy is a type that should be casted to integer
271/// around the atomic memory operation. If \param cmpxchg is true, then the
272/// cast of a floating point type is made as that instruction can not have
273/// floating point operands. TODO: Allow compare-and-exchange and FP - see
274/// comment in CIRGenAtomicExpandPass.cpp.
275static bool shouldCastToInt(mlir::Type valueTy, bool cmpxchg) {
276 if (cir::isAnyFloatingPointType(valueTy))
277 return isa<cir::FP80Type>(valueTy) || cmpxchg;
278 return !isa<cir::IntType>(valueTy) && !isa<cir::PointerType>(valueTy);
279}
280
281mlir::Value AtomicInfo::emitAtomicLoadOp(cir::MemOrder order, bool isVolatile,
282 bool cmpxchg) {
283 Address addr = getAtomicAddress();
284 if (shouldCastToInt(addr.getElementType(), cmpxchg))
285 addr = castToAtomicIntPointer(addr);
286
287 cir::LoadOp op =
288 cgf.getBuilder().createLoad(loc, addr, /*isVolatile=*/isVolatile);
289 op.setMemOrder(order);
290
292 return op;
293}
294
295mlir::Value AtomicInfo::convertRValueToInt(RValue rvalue, bool cmpxchg) const {
296 // If we've got a scalar value of the right size, try to avoid going
297 // through memory. Floats get casted if needed by AtomicExpandPass.
298 if (mlir::Value value = getScalarRValValueOrNull(rvalue)) {
299 if (!shouldCastToInt(value.getType(), cmpxchg))
300 return cgf.emitToMemory(value, valueTy);
301
302 cgf.cgm.errorNYI(
303 loc, "AtomicInfo::convertRValueToInt: cast scalar rvalue to int");
304 return nullptr;
305 }
306
307 cgf.cgm.errorNYI(
308 loc, "AtomicInfo::convertRValueToInt: cast non-scalar rvalue to int");
309 return nullptr;
310}
311
312RValue AtomicInfo::convertToValueOrAtomic(mlir::Value intVal,
313 AggValueSlot resultSlot,
314 SourceLocation loc, bool asValue,
315 bool cmpxchg) const {
316 // Try not to in some easy cases.
317 assert((mlir::isa<cir::IntType, cir::PointerType, cir::FPTypeInterface>(
318 intVal.getType())) &&
319 "Expected integer, pointer or floating point value when converting "
320 "result.");
321 bool isWholeValue =
322 !lvalue.isBitField() || lvalue.getBitFieldInfo().size == valueSizeInBits;
323 if (getEvaluationKind() == TEK_Scalar &&
324 ((isWholeValue && !hasPadding()) || !asValue)) {
325 mlir::Type valTy = asValue ? cgf.convertTypeForMem(valueTy)
326 : getAtomicAddress().getElementType();
327 if (!shouldCastToInt(valTy, cmpxchg)) {
328 assert((!mlir::isa<cir::IntType>(valTy) || intVal.getType() == valTy) &&
329 "Different integer types.");
330 return RValue::get(cgf.emitFromMemory(intVal, valueTy));
331 }
332
333 cgf.cgm.errorNYI("convertToValueOrAtomic: convert through bitcast");
334 return RValue::get(nullptr);
335 }
336
337 cgf.cgm.errorNYI("convertToValueOrAtomic: convert through temp");
338 return RValue::get(nullptr);
339}
340
341/// Copy an r-value into memory as part of storing to an atomic type.
342/// This needs to create a bit-pattern suitable for atomic operations.
343void AtomicInfo::emitCopyIntoMemory(RValue rvalue) const {
344 assert(lvalue.isSimple());
345
346 // If we have an r-value, the rvalue should be of the atomic type,
347 // which means that the caller is responsible for having zeroed
348 // any padding. Just do an aggregate copy of that type.
349 if (rvalue.isAggregate()) {
350 cgf.cgm.errorNYI("copying aggregate into atomic lvalue");
351 return;
352 }
353
354 // Okay, otherwise we're copying stuff.
355
356 // Zero out the buffer if necessary.
357 emitMemSetZeroIfNecessary();
358
359 // Drill past the padding if present.
360 LValue tempLValue = projectValue();
361
362 // Okay, store the rvalue in.
363 if (rvalue.isScalar()) {
364 cgf.emitStoreOfScalar(rvalue.getValue(), tempLValue, /*isInit=*/true);
365 } else {
366 cgf.emitStoreOfComplex(loc, rvalue.getComplexValue(), tempLValue,
367 /*isInit=*/true);
368 }
369}
370
371static void emitDefaultCaseLabel(CIRGenBuilderTy &builder, mlir::Location loc) {
372 mlir::ArrayAttr valuesAttr = builder.getArrayAttr({});
373 mlir::OpBuilder::InsertPoint insertPoint;
374 cir::CaseOp::create(builder, loc, valuesAttr, cir::CaseOpKind::Default,
375 insertPoint);
376 builder.restoreInsertionPoint(insertPoint);
377}
378
379// Create a "case" operation with the given list of orders as its values. Also
380// create the region that will hold the body of the switch-case label.
381static void emitMemOrderCaseLabel(CIRGenBuilderTy &builder, mlir::Location loc,
382 mlir::Type orderType,
385 for (cir::MemOrder order : orders)
386 orderAttrs.push_back(cir::IntAttr::get(orderType, static_cast<int>(order)));
387 mlir::ArrayAttr ordersAttr = builder.getArrayAttr(orderAttrs);
388
389 mlir::OpBuilder::InsertPoint insertPoint;
390 cir::CaseOp::create(builder, loc, ordersAttr, cir::CaseOpKind::Anyof,
391 insertPoint);
392 builder.restoreInsertionPoint(insertPoint);
393}
394
395static void emitAtomicCmpXchg(CIRGenFunction &cgf, AtomicExpr *e, bool isWeak,
396 Address dest, Address ptr, Address val1,
397 Address val2, uint64_t size,
398 cir::MemOrder successOrder,
399 cir::MemOrder failureOrder,
400 cir::SyncScopeKind scope) {
401 mlir::Location loc = cgf.getLoc(e->getSourceRange());
402
403 CIRGenBuilderTy &builder = cgf.getBuilder();
404 mlir::Value expected = builder.createLoad(loc, val1);
405 mlir::Value desired = builder.createLoad(loc, val2);
406
407 auto cmpxchg = cir::AtomicCmpXchgOp::create(
408 builder, loc, expected.getType(), builder.getBoolTy(), ptr.getPointer(),
409 expected, desired,
410 cir::MemOrderAttr::get(&cgf.getMLIRContext(), successOrder),
411 cir::MemOrderAttr::get(&cgf.getMLIRContext(), failureOrder),
412 cir::SyncScopeKindAttr::get(&cgf.getMLIRContext(), scope),
413 builder.getI64IntegerAttr(ptr.getAlignment().getAsAlign().value()));
414
415 cmpxchg.setIsVolatile(e->isVolatile());
416 cmpxchg.setWeak(isWeak);
417
418 mlir::Value failed = builder.createNot(cmpxchg.getSuccess());
419 cir::IfOp::create(builder, loc, failed, /*withElseRegion=*/false,
420 [&](mlir::OpBuilder &, mlir::Location) {
421 auto ptrTy = mlir::cast<cir::PointerType>(
422 val1.getPointer().getType());
423 if (val1.getElementType() != ptrTy.getPointee()) {
424 val1 = val1.withPointer(builder.createPtrBitcast(
425 val1.getPointer(), val1.getElementType()));
426 }
427 builder.createStore(loc, cmpxchg.getOld(), val1);
428 builder.createYield(loc);
429 });
430
431 // Update the memory at Dest with Success's value.
432 cgf.emitStoreOfScalar(cmpxchg.getSuccess(),
433 cgf.makeAddrLValue(dest, e->getType()),
434 /*isInit=*/false);
435}
436
438 bool isWeak, Address dest, Address ptr,
439 Address val1, Address val2,
440 Expr *failureOrderExpr, uint64_t size,
441 cir::MemOrder successOrder,
442 cir::SyncScopeKind scope) {
443 Expr::EvalResult failureOrderEval;
444 if (failureOrderExpr->EvaluateAsInt(failureOrderEval, cgf.getContext())) {
445 uint64_t failureOrderInt = failureOrderEval.Val.getInt().getZExtValue();
446
447 cir::MemOrder failureOrder;
448 if (!cir::isValidCIRAtomicOrderingCABI(failureOrderInt)) {
449 failureOrder = cir::MemOrder::Relaxed;
450 } else {
451 switch ((cir::MemOrder)failureOrderInt) {
452 case cir::MemOrder::Relaxed:
453 // 31.7.2.18: "The failure argument shall not be memory_order_release
454 // nor memory_order_acq_rel". Fallback to monotonic.
455 case cir::MemOrder::Release:
456 case cir::MemOrder::AcquireRelease:
457 failureOrder = cir::MemOrder::Relaxed;
458 break;
459 case cir::MemOrder::Consume:
460 case cir::MemOrder::Acquire:
461 failureOrder = cir::MemOrder::Acquire;
462 break;
463 case cir::MemOrder::SequentiallyConsistent:
464 failureOrder = cir::MemOrder::SequentiallyConsistent;
465 break;
466 }
467 }
468
469 // Prior to c++17, "the failure argument shall be no stronger than the
470 // success argument". This condition has been lifted and the only
471 // precondition is 31.7.2.18. Effectively treat this as a DR and skip
472 // language version checks.
473 emitAtomicCmpXchg(cgf, e, isWeak, dest, ptr, val1, val2, size, successOrder,
474 failureOrder, scope);
475 return;
476 }
477
478 // The failure memory order is not a compile time constant. The CIR atomic ops
479 // require a constant value, so that memory order is known at compile time. In
480 // this case, we can switch based on the memory order and call each variant
481 // individually.
482 mlir::Value failureOrderVal = cgf.emitScalarExpr(failureOrderExpr);
483 mlir::Location atomicLoc = cgf.getLoc(e->getSourceRange());
484 cir::SwitchOp::create(
485 cgf.getBuilder(), atomicLoc, failureOrderVal,
486 [&](mlir::OpBuilder &b, mlir::Location loc, mlir::OperationState &os) {
487 mlir::Block *switchBlock = cgf.getBuilder().getBlock();
488
489 // case cir::MemOrder::Relaxed:
490 // // 31.7.2.18: "The failure argument shall not be
491 // memory_order_release
492 // // nor memory_order_acq_rel". Fallback to monotonic.
493 // case cir::MemOrder::Release:
494 // case cir::MemOrder::AcquireRelease:
495 // Note: Since there are 3 options, this makes sense to just emit as a
496 // 'default', which prevents user code from 'falling off' of this,
497 // which seems reasonable. Also, 'relaxed' being the default behavior
498 // is also probably the least harmful.
499 emitDefaultCaseLabel(cgf.getBuilder(), atomicLoc);
500 emitAtomicCmpXchg(cgf, e, isWeak, dest, ptr, val1, val2, size,
501 successOrder, cir::MemOrder::Relaxed, scope);
502 cgf.getBuilder().createBreak(atomicLoc);
503 cgf.getBuilder().setInsertionPointToEnd(switchBlock);
504
505 // case cir::MemOrder::Consume:
506 // case cir::MemOrder::Acquire:
507 emitMemOrderCaseLabel(cgf.getBuilder(), loc, failureOrderVal.getType(),
508 {cir::MemOrder::Consume, cir::MemOrder::Acquire});
509 emitAtomicCmpXchg(cgf, e, isWeak, dest, ptr, val1, val2, size,
510 successOrder, cir::MemOrder::Acquire, scope);
511 cgf.getBuilder().createBreak(atomicLoc);
512 cgf.getBuilder().setInsertionPointToEnd(switchBlock);
513
514 // case cir::MemOrder::SequentiallyConsistent:
515 emitMemOrderCaseLabel(cgf.getBuilder(), loc, failureOrderVal.getType(),
516 {cir::MemOrder::SequentiallyConsistent});
517 emitAtomicCmpXchg(cgf, e, isWeak, dest, ptr, val1, val2, size,
518 successOrder, cir::MemOrder::SequentiallyConsistent,
519 scope);
520 cgf.getBuilder().createBreak(atomicLoc);
521 cgf.getBuilder().setInsertionPointToEnd(switchBlock);
522
523 cgf.getBuilder().createYield(atomicLoc);
524 });
525}
526
527// A version of the emitAtomicCmpXchgFailureSet function that ALSO checks
528// whether it is 'weak' or not (by adding an 'if' around it, and calling
529// emitAtomicCmpXchgFailureSet 2x).
531 CIRGenFunction &cgf, AtomicExpr *e, Expr *isWeakExpr, Address dest,
532 Address ptr, Address val1, Address val2, Expr *failureOrderExpr,
533 uint64_t size, cir::MemOrder successOrder, cir::SyncScopeKind scope) {
534 mlir::Value isWeakVal = cgf.emitScalarExpr(isWeakExpr);
535 // The AST seems to be inserting a 'bool' cast (even in C mode) here, so we'll
536 // just emit it like a scalar.
537 assert(isWeakVal.getType() == cgf.getBuilder().getBoolTy());
538 mlir::Location atomicLoc = cgf.getLoc(e->getSourceRange());
539
540 // Unlike classic compiler, we use an 'if' here instead of a switch, simply to
541 // make this more readable/logical, plus we don't allow switch over a bool in
542 // CIR.
543 cir::IfOp::create(
544 cgf.getBuilder(), atomicLoc, isWeakVal, /*elseRegion=*/true,
545 [&](mlir::OpBuilder &b, mlir::Location loc) {
546 emitAtomicCmpXchgFailureSet(cgf, e, /*isWeak=*/true, dest, ptr, val1,
547 val2, failureOrderExpr, size, successOrder,
548 scope);
549 cgf.getBuilder().createYield(atomicLoc);
550 },
551 [&](mlir::OpBuilder &b, mlir::Location loc) {
552 emitAtomicCmpXchgFailureSet(cgf, e, /*isWeak=*/false, dest, ptr, val1,
553 val2, failureOrderExpr, size, successOrder,
554 scope);
555 cgf.getBuilder().createYield(atomicLoc);
556 });
557}
558
560 Address ptr, Address val1, Address val2,
561 Expr *isWeakExpr, Expr *failureOrderExpr, int64_t size,
562 cir::MemOrder order, cir::SyncScopeKind scope) {
564 llvm::StringRef opName;
565
566 CIRGenBuilderTy &builder = cgf.getBuilder();
567 mlir::Location loc = cgf.getLoc(expr->getSourceRange());
568 auto orderAttr = cir::MemOrderAttr::get(builder.getContext(), order);
569 auto scopeAttr = cir::SyncScopeKindAttr::get(builder.getContext(), scope);
570 cir::AtomicFetchKindAttr fetchAttr;
571 bool fetchFirst = true;
572
573 auto handleFetchOp = [&](cir::AtomicFetchKind kind) {
574 opName = cir::AtomicFetchOp::getOperationName();
575 fetchAttr = cir::AtomicFetchKindAttr::get(builder.getContext(), kind);
576 };
577
578 switch (expr->getOp()) {
579 case AtomicExpr::AO__c11_atomic_init:
580 llvm_unreachable("already handled!");
581
582 case AtomicExpr::AO__c11_atomic_compare_exchange_strong:
583 emitAtomicCmpXchgFailureSet(cgf, expr, /*isWeak=*/false, dest, ptr, val1,
584 val2, failureOrderExpr, size, order, scope);
585 return;
586
587 case AtomicExpr::AO__c11_atomic_compare_exchange_weak:
588 emitAtomicCmpXchgFailureSet(cgf, expr, /*isWeak=*/true, dest, ptr, val1,
589 val2, failureOrderExpr, size, order, scope);
590 return;
591
592 case AtomicExpr::AO__atomic_compare_exchange:
593 case AtomicExpr::AO__atomic_compare_exchange_n:
594 case AtomicExpr::AO__scoped_atomic_compare_exchange:
595 case AtomicExpr::AO__scoped_atomic_compare_exchange_n: {
596 bool isWeak = false;
597 if (isWeakExpr->EvaluateAsBooleanCondition(isWeak, cgf.getContext())) {
598 emitAtomicCmpXchgFailureSet(cgf, expr, isWeak, dest, ptr, val1, val2,
599 failureOrderExpr, size, order, scope);
600 } else {
601 emitAtomicCmpXchgFailureSetCheckWeak(cgf, expr, isWeakExpr, dest, ptr,
602 val1, val2, failureOrderExpr, size,
603 order, scope);
604 }
605 return;
606 }
607
608 case AtomicExpr::AO__c11_atomic_load:
609 case AtomicExpr::AO__atomic_load_n:
610 case AtomicExpr::AO__atomic_load:
611 case AtomicExpr::AO__scoped_atomic_load_n:
612 case AtomicExpr::AO__scoped_atomic_load: {
613 cir::LoadOp load =
614 builder.createLoad(loc, ptr, /*isVolatile=*/expr->isVolatile());
615
616 load->setAttr("mem_order", orderAttr);
617 load->setAttr("sync_scope", scopeAttr);
618
619 builder.createStore(loc, load->getResult(0), dest);
620 return;
621 }
622
623 case AtomicExpr::AO__c11_atomic_store:
624 case AtomicExpr::AO__atomic_store_n:
625 case AtomicExpr::AO__atomic_store:
626 case AtomicExpr::AO__scoped_atomic_store:
627 case AtomicExpr::AO__scoped_atomic_store_n: {
628 cir::LoadOp loadVal1 = builder.createLoad(loc, val1);
629
631
632 builder.createStore(loc, loadVal1, ptr, expr->isVolatile(),
633 /*align=*/mlir::IntegerAttr{}, scopeAttr, orderAttr);
634 return;
635 }
636
637 case AtomicExpr::AO__c11_atomic_exchange:
638 case AtomicExpr::AO__atomic_exchange_n:
639 case AtomicExpr::AO__atomic_exchange:
640 case AtomicExpr::AO__scoped_atomic_exchange_n:
641 case AtomicExpr::AO__scoped_atomic_exchange:
642 opName = cir::AtomicXchgOp::getOperationName();
643 break;
644
645 case AtomicExpr::AO__atomic_add_fetch:
646 case AtomicExpr::AO__scoped_atomic_add_fetch:
647 fetchFirst = false;
648 [[fallthrough]];
649 case AtomicExpr::AO__c11_atomic_fetch_add:
650 case AtomicExpr::AO__atomic_fetch_add:
651 case AtomicExpr::AO__scoped_atomic_fetch_add:
652 handleFetchOp(cir::AtomicFetchKind::Add);
653 break;
654
655 case AtomicExpr::AO__atomic_sub_fetch:
656 case AtomicExpr::AO__scoped_atomic_sub_fetch:
657 fetchFirst = false;
658 [[fallthrough]];
659 case AtomicExpr::AO__c11_atomic_fetch_sub:
660 case AtomicExpr::AO__atomic_fetch_sub:
661 case AtomicExpr::AO__scoped_atomic_fetch_sub:
662 handleFetchOp(cir::AtomicFetchKind::Sub);
663 break;
664
665 case AtomicExpr::AO__atomic_min_fetch:
666 case AtomicExpr::AO__scoped_atomic_min_fetch:
667 fetchFirst = false;
668 [[fallthrough]];
669 case AtomicExpr::AO__c11_atomic_fetch_min:
670 case AtomicExpr::AO__atomic_fetch_min:
671 case AtomicExpr::AO__scoped_atomic_fetch_min:
672 handleFetchOp(cir::AtomicFetchKind::Min);
673 break;
674
675 case AtomicExpr::AO__atomic_max_fetch:
676 case AtomicExpr::AO__scoped_atomic_max_fetch:
677 fetchFirst = false;
678 [[fallthrough]];
679 case AtomicExpr::AO__c11_atomic_fetch_max:
680 case AtomicExpr::AO__atomic_fetch_max:
681 case AtomicExpr::AO__scoped_atomic_fetch_max:
682 handleFetchOp(cir::AtomicFetchKind::Max);
683 break;
684
685 case AtomicExpr::AO__atomic_and_fetch:
686 case AtomicExpr::AO__scoped_atomic_and_fetch:
687 fetchFirst = false;
688 [[fallthrough]];
689 case AtomicExpr::AO__c11_atomic_fetch_and:
690 case AtomicExpr::AO__atomic_fetch_and:
691 case AtomicExpr::AO__scoped_atomic_fetch_and:
692 handleFetchOp(cir::AtomicFetchKind::And);
693 break;
694
695 case AtomicExpr::AO__atomic_or_fetch:
696 case AtomicExpr::AO__scoped_atomic_or_fetch:
697 fetchFirst = false;
698 [[fallthrough]];
699 case AtomicExpr::AO__c11_atomic_fetch_or:
700 case AtomicExpr::AO__atomic_fetch_or:
701 case AtomicExpr::AO__scoped_atomic_fetch_or:
702 handleFetchOp(cir::AtomicFetchKind::Or);
703 break;
704
705 case AtomicExpr::AO__atomic_xor_fetch:
706 case AtomicExpr::AO__scoped_atomic_xor_fetch:
707 fetchFirst = false;
708 [[fallthrough]];
709 case AtomicExpr::AO__c11_atomic_fetch_xor:
710 case AtomicExpr::AO__atomic_fetch_xor:
711 case AtomicExpr::AO__scoped_atomic_fetch_xor:
712 handleFetchOp(cir::AtomicFetchKind::Xor);
713 break;
714
715 case AtomicExpr::AO__atomic_nand_fetch:
716 case AtomicExpr::AO__scoped_atomic_nand_fetch:
717 fetchFirst = false;
718 [[fallthrough]];
719 case AtomicExpr::AO__c11_atomic_fetch_nand:
720 case AtomicExpr::AO__atomic_fetch_nand:
721 case AtomicExpr::AO__scoped_atomic_fetch_nand:
722 handleFetchOp(cir::AtomicFetchKind::Nand);
723 break;
724
725 case AtomicExpr::AO__atomic_test_and_set: {
726 auto op = cir::AtomicTestAndSetOp::create(
727 builder, loc, ptr.getPointer(), order,
728 builder.getI64IntegerAttr(ptr.getAlignment().getQuantity()),
729 expr->isVolatile());
730 builder.createStore(loc, op, dest);
731 return;
732 }
733
734 case AtomicExpr::AO__atomic_clear: {
735 cir::AtomicClearOp::create(
736 builder, loc, ptr.getPointer(), order,
737 builder.getI64IntegerAttr(ptr.getAlignment().getQuantity()),
738 expr->isVolatile());
739 return;
740 }
741
742 case AtomicExpr::AO__atomic_fetch_uinc:
743 case AtomicExpr::AO__scoped_atomic_fetch_uinc:
744 handleFetchOp(cir::AtomicFetchKind::UIncWrap);
745 break;
746
747 case AtomicExpr::AO__atomic_fetch_udec:
748 case AtomicExpr::AO__scoped_atomic_fetch_udec:
749 handleFetchOp(cir::AtomicFetchKind::UDecWrap);
750 break;
751
752 case AtomicExpr::AO__opencl_atomic_init:
753
754 case AtomicExpr::AO__hip_atomic_compare_exchange_strong:
755 case AtomicExpr::AO__opencl_atomic_compare_exchange_strong:
756
757 case AtomicExpr::AO__opencl_atomic_compare_exchange_weak:
758 case AtomicExpr::AO__hip_atomic_compare_exchange_weak:
759
760 case AtomicExpr::AO__opencl_atomic_load:
761 case AtomicExpr::AO__hip_atomic_load:
762
763 case AtomicExpr::AO__opencl_atomic_store:
764 case AtomicExpr::AO__hip_atomic_store:
765
766 case AtomicExpr::AO__hip_atomic_exchange:
767 case AtomicExpr::AO__opencl_atomic_exchange:
768
769 case AtomicExpr::AO__hip_atomic_fetch_add:
770 case AtomicExpr::AO__opencl_atomic_fetch_add:
771
772 case AtomicExpr::AO__hip_atomic_fetch_sub:
773 case AtomicExpr::AO__opencl_atomic_fetch_sub:
774
775 case AtomicExpr::AO__hip_atomic_fetch_min:
776 case AtomicExpr::AO__opencl_atomic_fetch_min:
777
778 case AtomicExpr::AO__hip_atomic_fetch_max:
779 case AtomicExpr::AO__opencl_atomic_fetch_max:
780
781 case AtomicExpr::AO__hip_atomic_fetch_and:
782 case AtomicExpr::AO__opencl_atomic_fetch_and:
783
784 case AtomicExpr::AO__hip_atomic_fetch_or:
785 case AtomicExpr::AO__opencl_atomic_fetch_or:
786
787 case AtomicExpr::AO__hip_atomic_fetch_xor:
788 case AtomicExpr::AO__opencl_atomic_fetch_xor:
789 cgf.cgm.errorNYI(expr->getSourceRange(), "emitAtomicOp: expr op NYI");
790 return;
791 }
792
793 assert(!opName.empty() && "expected operation name to build");
794 mlir::Value loadVal1 = builder.createLoad(loc, val1);
795
796 SmallVector<mlir::Value> atomicOperands = {ptr.getPointer(), loadVal1};
797 SmallVector<mlir::Type> atomicResTys = {loadVal1.getType()};
798 mlir::Operation *rmwOp = builder.create(loc, builder.getStringAttr(opName),
799 atomicOperands, atomicResTys);
800
801 if (fetchAttr)
802 rmwOp->setAttr("binop", fetchAttr);
803 rmwOp->setAttr("mem_order", orderAttr);
804 rmwOp->setAttr("sync_scope", scopeAttr);
805 if (expr->isVolatile())
806 rmwOp->setAttr("is_volatile", builder.getUnitAttr());
807 if (fetchFirst && opName == cir::AtomicFetchOp::getOperationName())
808 rmwOp->setAttr("fetch_first", builder.getUnitAttr());
809
810 mlir::Value result = rmwOp->getResult(0);
811
812 builder.createStore(loc, result, dest);
813}
814
815// Map clang sync scope to CIR sync scope.
816static cir::SyncScopeKind convertSyncScopeToCIR(CIRGenFunction &cgf,
817 SourceRange range,
818 clang::SyncScope scope) {
819 switch (scope) {
821 return cir::SyncScopeKind::SingleThread;
823 return cir::SyncScopeKind::System;
825 return cir::SyncScopeKind::Device;
827 return cir::SyncScopeKind::Workgroup;
829 return cir::SyncScopeKind::Wavefront;
831 return cir::SyncScopeKind::Cluster;
832
834 return cir::SyncScopeKind::HIPSingleThread;
836 return cir::SyncScopeKind::HIPSystem;
838 return cir::SyncScopeKind::HIPAgent;
840 return cir::SyncScopeKind::HIPWorkgroup;
842 return cir::SyncScopeKind::HIPWavefront;
844 return cir::SyncScopeKind::HIPCluster;
845
847 return cir::SyncScopeKind::OpenCLWorkGroup;
849 return cir::SyncScopeKind::OpenCLDevice;
851 return cir::SyncScopeKind::OpenCLAllSVMDevices;
853 return cir::SyncScopeKind::OpenCLSubGroup;
854 }
855
856 llvm_unreachable("unhandled sync scope");
857}
858
860 Address ptr, Address val1, Address val2,
861 Expr *isWeakExpr, Expr *failureOrderExpr, int64_t size,
862 cir::MemOrder order,
863 const std::optional<Expr::EvalResult> &scopeConst,
864 mlir::Value scopeValue) {
865 std::unique_ptr<AtomicScopeModel> scopeModel = expr->getScopeModel();
866
867 if (!scopeModel) {
868 emitAtomicOp(cgf, expr, dest, ptr, val1, val2, isWeakExpr, failureOrderExpr,
869 size, order, cir::SyncScopeKind::System);
870 return;
871 }
872
873 if (scopeConst.has_value()) {
874 cir::SyncScopeKind mappedScope = convertSyncScopeToCIR(
875 cgf, expr->getScope()->getSourceRange(),
876 scopeModel->map(scopeConst->Val.getInt().getZExtValue()));
877 emitAtomicOp(cgf, expr, dest, ptr, val1, val2, isWeakExpr, failureOrderExpr,
878 size, order, mappedScope);
879 return;
880 }
881
882 // The sync scope is not a compile-time constant. Emit a switch statement to
883 // handle each possible value of the sync scope.
884 CIRGenBuilderTy &builder = cgf.getBuilder();
885 mlir::Location loc = cgf.getLoc(expr->getSourceRange());
886 llvm::ArrayRef<unsigned> allScopes = scopeModel->getRuntimeValues();
887 unsigned fallback = scopeModel->getFallBackValue();
888
889 cir::SwitchOp::create(
890 builder, loc, scopeValue,
891 [&](mlir::OpBuilder &, mlir::Location loc, mlir::OperationState &) {
892 mlir::Block *switchBlock = builder.getBlock();
893
894 // Default case -- use fallback scope
895 cir::SyncScopeKind fallbackScope = convertSyncScopeToCIR(
896 cgf, expr->getScope()->getSourceRange(), scopeModel->map(fallback));
897 emitDefaultCaseLabel(builder, loc);
898 emitAtomicOp(cgf, expr, dest, ptr, val1, val2, isWeakExpr,
899 failureOrderExpr, size, order, fallbackScope);
900 builder.createBreak(loc);
901 builder.setInsertionPointToEnd(switchBlock);
902
903 // Emit a switch case for each non-fallback runtime scope value
904 for (unsigned scope : allScopes) {
905 if (scope == fallback)
906 continue;
907
908 cir::SyncScopeKind cirScope = convertSyncScopeToCIR(
909 cgf, expr->getScope()->getSourceRange(), scopeModel->map(scope));
910
911 mlir::ArrayAttr casesAttr = builder.getArrayAttr(
912 {cir::IntAttr::get(scopeValue.getType(), scope)});
913 mlir::OpBuilder::InsertPoint insertPoint;
914 cir::CaseOp::create(builder, loc, casesAttr, cir::CaseOpKind::Equal,
915 insertPoint);
916
917 builder.restoreInsertionPoint(insertPoint);
918 emitAtomicOp(cgf, expr, dest, ptr, val1, val2, isWeakExpr,
919 failureOrderExpr, size, order, cirScope);
920 builder.createBreak(loc);
921 builder.setInsertionPointToEnd(switchBlock);
922 }
923
924 builder.createYield(loc);
925 });
926}
927
928static std::optional<cir::MemOrder>
929getEffectiveAtomicMemOrder(cir::MemOrder oriOrder, bool isStore, bool isLoad,
930 bool isFence) {
931 // Some memory orders are not supported by partial atomic operation:
932 // {memory_order_releaxed} is not valid for fence operations.
933 // {memory_order_consume, memory_order_acquire} are not valid for write-only
934 // operations.
935 // {memory_order_release} is not valid for read-only operations.
936 // {memory_order_acq_rel} is only valid for read-write operations.
937 if (isStore) {
938 if (oriOrder == cir::MemOrder::Consume ||
939 oriOrder == cir::MemOrder::Acquire ||
940 oriOrder == cir::MemOrder::AcquireRelease)
941 return std::nullopt;
942 } else if (isLoad) {
943 if (oriOrder == cir::MemOrder::Release ||
944 oriOrder == cir::MemOrder::AcquireRelease)
945 return std::nullopt;
946 } else if (isFence) {
947 if (oriOrder == cir::MemOrder::Relaxed)
948 return std::nullopt;
949 }
950 // memory_order_consume is not implemented, it is always treated like
951 // memory_order_acquire
952 if (oriOrder == cir::MemOrder::Consume)
953 return cir::MemOrder::Acquire;
954 return oriOrder;
955}
956
958 CIRGenFunction &cgf, mlir::Value order, bool isStore, bool isLoad,
959 bool isFence, llvm::function_ref<void(cir::MemOrder)> emitAtomicOpFn) {
960 if (!order)
961 return;
962 // The memory order is not known at compile-time. The atomic operations
963 // can't handle runtime memory orders; the memory order must be hard coded.
964 // Generate a "switch" statement that converts a runtime value into a
965 // compile-time value.
966 CIRGenBuilderTy &builder = cgf.getBuilder();
967 cir::SwitchOp::create(
968 builder, order.getLoc(), order,
969 [&](mlir::OpBuilder &, mlir::Location loc, mlir::OperationState &) {
970 mlir::Block *switchBlock = builder.getBlock();
971
972 auto emitMemOrderCase = [&](llvm::ArrayRef<cir::MemOrder> caseOrders) {
973 // Checking there are same effective memory order for each case.
974 for (int i = 1, e = caseOrders.size(); i < e; i++)
975 assert((getEffectiveAtomicMemOrder(caseOrders[i - 1], isStore,
976 isLoad, isFence) ==
977 getEffectiveAtomicMemOrder(caseOrders[i], isStore, isLoad,
978 isFence)) &&
979 "Effective memory order must be same!");
980 // Emit case label and atomic opeartion if neccessary.
981 if (caseOrders.empty()) {
982 emitDefaultCaseLabel(builder, loc);
983 // There is no good way to report an unsupported memory order at
984 // runtime, hence the fallback to memory_order_relaxed.
985 if (!isFence)
986 emitAtomicOpFn(cir::MemOrder::Relaxed);
987 } else if (std::optional<cir::MemOrder> actualOrder =
988 getEffectiveAtomicMemOrder(caseOrders[0], isStore,
989 isLoad, isFence)) {
990 // Included in default case.
991 if (!isFence && actualOrder == cir::MemOrder::Relaxed)
992 return;
993 // Creating case operation for effective memory order. If there are
994 // multiple cases in `caseOrders`, the actual order of each case
995 // must be same, this needs to be guaranteed by the caller.
996 emitMemOrderCaseLabel(builder, loc, order.getType(), caseOrders);
997 emitAtomicOpFn(actualOrder.value());
998 } else {
999 // Do nothing if (!caseOrders.empty() && !actualOrder)
1000 return;
1001 }
1002 builder.createBreak(loc);
1003 builder.setInsertionPointToEnd(switchBlock);
1004 };
1005
1006 emitMemOrderCase(/*default:*/ {});
1007 emitMemOrderCase({cir::MemOrder::Relaxed});
1008 emitMemOrderCase({cir::MemOrder::Consume, cir::MemOrder::Acquire});
1009 emitMemOrderCase({cir::MemOrder::Release});
1010 emitMemOrderCase({cir::MemOrder::AcquireRelease});
1011 emitMemOrderCase({cir::MemOrder::SequentiallyConsistent});
1012
1013 builder.createYield(loc);
1014 });
1015}
1016
1018 const Expr *memOrder, bool isStore, bool isLoad, bool isFence,
1019 llvm::function_ref<void(cir::MemOrder)> emitAtomicOpFn) {
1020 // Emit the memory order operand, and try to evaluate it as a constant.
1021 Expr::EvalResult eval;
1022 if (memOrder->EvaluateAsInt(eval, getContext())) {
1023 uint64_t constOrder = eval.Val.getInt().getZExtValue();
1024 // We should not ever get to a case where the ordering isn't a valid CABI
1025 // value, but it's hard to enforce that in general.
1026 if (!cir::isValidCIRAtomicOrderingCABI(constOrder))
1027 return;
1028 cir::MemOrder oriOrder = static_cast<cir::MemOrder>(constOrder);
1029 if (std::optional<cir::MemOrder> actualOrder =
1030 getEffectiveAtomicMemOrder(oriOrder, isStore, isLoad, isFence))
1031 emitAtomicOpFn(actualOrder.value());
1032 return;
1033 }
1034
1035 // Otherwise, handle variable memory ordering. Emit `SwitchOp` to convert
1036 // dynamic value to static value.
1037 mlir::Value dynOrder = emitScalarExpr(memOrder);
1038 emitAtomicExprWithDynamicMemOrder(*this, dynOrder, isStore, isLoad, isFence,
1039 emitAtomicOpFn);
1040}
1041
1043 QualType atomicTy = e->getPtr()->getType()->getPointeeType();
1044 QualType memTy = atomicTy;
1045 if (const auto *ty = atomicTy->getAs<AtomicType>())
1046 memTy = ty->getValueType();
1047
1048 Expr *isWeakExpr = nullptr;
1049 Expr *orderFailExpr = nullptr;
1050
1051 Address val1 = Address::invalid();
1052 Address val2 = Address::invalid();
1053 Address dest = Address::invalid();
1055
1057 if (e->getOp() == AtomicExpr::AO__c11_atomic_init) {
1058 LValue lvalue = makeAddrLValue(ptr, atomicTy);
1059 emitAtomicInit(e->getVal1(), lvalue);
1060 return RValue::get(nullptr);
1061 }
1062
1063 TypeInfoChars typeInfo = getContext().getTypeInfoInChars(atomicTy);
1064 uint64_t size = typeInfo.Width.getQuantity();
1065
1066 // Emit the sync scope operand, and try to evaluate it as a constant.
1067 mlir::Value scope =
1068 e->getScopeModel() ? emitScalarExpr(e->getScope()) : nullptr;
1069 std::optional<Expr::EvalResult> scopeConst;
1070 if (Expr::EvalResult eval;
1071 e->getScopeModel() && e->getScope()->EvaluateAsInt(eval, getContext()))
1072 scopeConst.emplace(std::move(eval));
1073
1074 switch (e->getOp()) {
1075 default:
1076 cgm.errorNYI(e->getSourceRange(), "atomic op NYI");
1077 return RValue::get(nullptr);
1078
1079 case AtomicExpr::AO__c11_atomic_init:
1080 llvm_unreachable("already handled above with emitAtomicInit");
1081
1082 case AtomicExpr::AO__atomic_load_n:
1083 case AtomicExpr::AO__scoped_atomic_load_n:
1084 case AtomicExpr::AO__c11_atomic_load:
1085 case AtomicExpr::AO__atomic_test_and_set:
1086 case AtomicExpr::AO__atomic_clear:
1087 break;
1088
1089 case AtomicExpr::AO__atomic_load:
1090 case AtomicExpr::AO__scoped_atomic_load:
1091 dest = emitPointerWithAlignment(e->getVal1());
1092 break;
1093
1094 case AtomicExpr::AO__atomic_store:
1095 case AtomicExpr::AO__scoped_atomic_store:
1096 val1 = emitPointerWithAlignment(e->getVal1());
1097 break;
1098
1099 case AtomicExpr::AO__atomic_exchange:
1100 case AtomicExpr::AO__scoped_atomic_exchange:
1101 val1 = emitPointerWithAlignment(e->getVal1());
1102 dest = emitPointerWithAlignment(e->getVal2());
1103 break;
1104
1105 case AtomicExpr::AO__atomic_compare_exchange:
1106 case AtomicExpr::AO__atomic_compare_exchange_n:
1107 case AtomicExpr::AO__c11_atomic_compare_exchange_weak:
1108 case AtomicExpr::AO__c11_atomic_compare_exchange_strong:
1109 case AtomicExpr::AO__scoped_atomic_compare_exchange:
1110 case AtomicExpr::AO__scoped_atomic_compare_exchange_n:
1111 val1 = emitPointerWithAlignment(e->getVal1());
1112 if (e->getOp() == AtomicExpr::AO__atomic_compare_exchange ||
1113 e->getOp() == AtomicExpr::AO__scoped_atomic_compare_exchange)
1114 val2 = emitPointerWithAlignment(e->getVal2());
1115 else
1116 val2 = emitValToTemp(*this, e->getVal2());
1117 orderFailExpr = e->getOrderFail();
1118 if (e->getOp() == AtomicExpr::AO__atomic_compare_exchange_n ||
1119 e->getOp() == AtomicExpr::AO__atomic_compare_exchange ||
1120 e->getOp() == AtomicExpr::AO__scoped_atomic_compare_exchange_n ||
1121 e->getOp() == AtomicExpr::AO__scoped_atomic_compare_exchange)
1122 isWeakExpr = e->getWeak();
1123 break;
1124
1125 case AtomicExpr::AO__c11_atomic_fetch_add:
1126 case AtomicExpr::AO__c11_atomic_fetch_sub:
1127 if (memTy->isPointerType()) {
1128 // For pointer arithmetic, we're required to do a bit of math:
1129 // adding 1 to an int* is not the same as adding 1 to a uintptr_t.
1130 // ... but only for the C11 builtins. The GNU builtins expect the
1131 // user to multiply by sizeof(T).
1132 QualType val1Ty = e->getVal1()->getType();
1133 mlir::Location loc = getLoc(e->getSourceRange());
1134 mlir::Value val1Scalar = emitScalarExpr(e->getVal1());
1135 CharUnits pointeeIncAmt =
1136 getContext().getTypeSizeInChars(memTy->getPointeeType());
1137 mlir::Value scale = builder.getConstInt(loc, val1Scalar.getType(),
1138 pointeeIncAmt.getQuantity());
1139 val1Scalar = builder.createMul(loc, val1Scalar, scale);
1140 val1 = createMemTemp(val1Ty, loc, ".atomictmp");
1141 emitStoreOfScalar(val1Scalar, makeAddrLValue(val1, val1Ty),
1142 /*isInit=*/true);
1143 }
1144 [[fallthrough]];
1145 case AtomicExpr::AO__atomic_fetch_add:
1146 case AtomicExpr::AO__atomic_fetch_sub:
1147 case AtomicExpr::AO__atomic_add_fetch:
1148 case AtomicExpr::AO__atomic_sub_fetch:
1149 if (memTy->isPointerType()) {
1150 // Fetch-and-update atomic operation on pointers should treat the pointer
1151 // value as uintptr_t values
1152 if (!val1.isValid())
1153 val1 = emitValToTemp(*this, e->getVal1());
1154 ptr = ptr.withElementType(builder, val1.getElementType());
1155 break;
1156 }
1157 [[fallthrough]];
1158 case AtomicExpr::AO__atomic_fetch_max:
1159 case AtomicExpr::AO__atomic_fetch_min:
1160 case AtomicExpr::AO__atomic_max_fetch:
1161 case AtomicExpr::AO__atomic_min_fetch:
1162 case AtomicExpr::AO__c11_atomic_fetch_max:
1163 case AtomicExpr::AO__c11_atomic_fetch_min:
1164 case AtomicExpr::AO__scoped_atomic_fetch_add:
1165 case AtomicExpr::AO__scoped_atomic_fetch_max:
1166 case AtomicExpr::AO__scoped_atomic_fetch_min:
1167 case AtomicExpr::AO__scoped_atomic_fetch_sub:
1168 case AtomicExpr::AO__scoped_atomic_add_fetch:
1169 case AtomicExpr::AO__scoped_atomic_max_fetch:
1170 case AtomicExpr::AO__scoped_atomic_min_fetch:
1171 case AtomicExpr::AO__scoped_atomic_sub_fetch:
1172 [[fallthrough]];
1173
1174 case AtomicExpr::AO__atomic_fetch_and:
1175 case AtomicExpr::AO__atomic_fetch_nand:
1176 case AtomicExpr::AO__atomic_fetch_or:
1177 case AtomicExpr::AO__atomic_fetch_xor:
1178 case AtomicExpr::AO__atomic_and_fetch:
1179 case AtomicExpr::AO__atomic_nand_fetch:
1180 case AtomicExpr::AO__atomic_or_fetch:
1181 case AtomicExpr::AO__atomic_xor_fetch:
1182 case AtomicExpr::AO__atomic_exchange_n:
1183 case AtomicExpr::AO__atomic_store_n:
1184 case AtomicExpr::AO__c11_atomic_fetch_and:
1185 case AtomicExpr::AO__c11_atomic_fetch_nand:
1186 case AtomicExpr::AO__c11_atomic_fetch_or:
1187 case AtomicExpr::AO__c11_atomic_fetch_xor:
1188 case AtomicExpr::AO__c11_atomic_exchange:
1189 case AtomicExpr::AO__c11_atomic_store:
1190 case AtomicExpr::AO__scoped_atomic_fetch_and:
1191 case AtomicExpr::AO__scoped_atomic_fetch_nand:
1192 case AtomicExpr::AO__scoped_atomic_fetch_or:
1193 case AtomicExpr::AO__scoped_atomic_fetch_xor:
1194 case AtomicExpr::AO__scoped_atomic_and_fetch:
1195 case AtomicExpr::AO__scoped_atomic_nand_fetch:
1196 case AtomicExpr::AO__scoped_atomic_or_fetch:
1197 case AtomicExpr::AO__scoped_atomic_xor_fetch:
1198 case AtomicExpr::AO__scoped_atomic_store_n:
1199 case AtomicExpr::AO__scoped_atomic_exchange_n:
1200 case AtomicExpr::AO__atomic_fetch_uinc:
1201 case AtomicExpr::AO__atomic_fetch_udec:
1202 case AtomicExpr::AO__scoped_atomic_fetch_uinc:
1203 case AtomicExpr::AO__scoped_atomic_fetch_udec:
1204 val1 = emitValToTemp(*this, e->getVal1());
1205 break;
1206 }
1207
1208 QualType resultTy = e->getType().getUnqualifiedType();
1209
1210 bool shouldCastToIntPtrTy =
1212
1213 // The inlined atomics only function on iN types, where N is a power of 2. We
1214 // need to make sure (via temporaries if necessary) that all incoming values
1215 // are compatible.
1216 LValue atomicValue = makeAddrLValue(ptr, atomicTy);
1217 AtomicInfo atomics(*this, atomicValue, getLoc(e->getSourceRange()));
1218
1219 if (shouldCastToIntPtrTy) {
1220 ptr = atomics.castToAtomicIntPointer(ptr);
1221 if (val1.isValid())
1222 val1 = atomics.convertToAtomicIntPointer(val1);
1223 if (val2.isValid())
1224 val2 = atomics.convertToAtomicIntPointer(val2);
1225 }
1226 if (dest.isValid()) {
1227 if (shouldCastToIntPtrTy)
1228 dest = atomics.castToAtomicIntPointer(dest);
1229 } else if (e->isCmpXChg()) {
1230 dest = createMemTemp(resultTy, getLoc(e->getSourceRange()), "cmpxchg.bool");
1231 } else if (e->getOp() == AtomicExpr::AO__atomic_test_and_set) {
1232 dest = createMemTemp(resultTy, getLoc(e->getSourceRange()),
1233 "test_and_set.bool");
1234 } else if (!resultTy->isVoidType()) {
1235 dest = atomics.createTempAlloca();
1236 if (shouldCastToIntPtrTy)
1237 dest = atomics.castToAtomicIntPointer(dest);
1238 }
1239
1240 bool powerOf2Size = (size & (size - 1)) == 0;
1241 bool useLibCall = !powerOf2Size || (size > 16);
1242
1243 // For atomics larger than 16 bytes, emit a libcall from the frontend. This
1244 // avoids the overhead of dealing with excessively-large value types in IR.
1245 // Non-power-of-2 values also lower to libcall here, as they are not currently
1246 // permitted in IR instructions (although that constraint could be relaxed in
1247 // the future). For other cases where a libcall is required on a given
1248 // platform, we let the backend handle it (this includes handling for all of
1249 // the size-optimized libcall variants, which are only valid up to 16 bytes.)
1250 //
1251 // See: https://llvm.org/docs/Atomics.html#libcalls-atomic
1252 if (useLibCall) {
1254 cgm.errorNYI(e->getSourceRange(), "emitAtomicExpr: emit atomic lib call");
1255 return RValue::get(nullptr);
1256 }
1257
1258 bool isStore = e->getOp() == AtomicExpr::AO__c11_atomic_store ||
1259 e->getOp() == AtomicExpr::AO__opencl_atomic_store ||
1260 e->getOp() == AtomicExpr::AO__hip_atomic_store ||
1261 e->getOp() == AtomicExpr::AO__atomic_store ||
1262 e->getOp() == AtomicExpr::AO__atomic_store_n ||
1263 e->getOp() == AtomicExpr::AO__scoped_atomic_store ||
1264 e->getOp() == AtomicExpr::AO__scoped_atomic_store_n ||
1265 e->getOp() == AtomicExpr::AO__atomic_clear;
1266 bool isLoad = e->getOp() == AtomicExpr::AO__c11_atomic_load ||
1267 e->getOp() == AtomicExpr::AO__opencl_atomic_load ||
1268 e->getOp() == AtomicExpr::AO__hip_atomic_load ||
1269 e->getOp() == AtomicExpr::AO__atomic_load ||
1270 e->getOp() == AtomicExpr::AO__atomic_load_n ||
1271 e->getOp() == AtomicExpr::AO__scoped_atomic_load ||
1272 e->getOp() == AtomicExpr::AO__scoped_atomic_load_n;
1273
1274 auto emitAtomicOpCallBackFn = [&](cir::MemOrder memOrder) {
1275 emitAtomicOp(*this, e, dest, ptr, val1, val2, isWeakExpr, orderFailExpr,
1276 size, memOrder, scopeConst, scope);
1277 };
1278 emitAtomicExprWithMemOrder(e->getOrder(), isStore, isLoad, /*isFence*/ false,
1279 emitAtomicOpCallBackFn);
1280
1281 if (resultTy->isVoidType())
1282 return RValue::get(nullptr);
1283
1284 return convertTempToRValue(
1285 dest.withElementType(builder, convertTypeForMem(resultTy)), resultTy,
1286 e->getExprLoc());
1287}
1288
1290 AggValueSlot slot) {
1291 if (lvalue.getType()->isAtomicType())
1292 return emitAtomicLoad(lvalue, loc, cir::MemOrder::SequentiallyConsistent,
1293 /*isVolatile=*/lvalue.isVolatileQualified(), slot);
1294 return emitAtomicLoad(lvalue, loc, cir::MemOrder::Acquire,
1295 /*isVolatile=*/true, slot);
1296}
1297
1299 cir::MemOrder order, bool isVolatile,
1300 AggValueSlot slot) {
1301 AtomicInfo info(*this, lvalue, getLoc(loc));
1302 return info.emitAtomicLoad(slot, loc, /*asValue=*/true, order, isVolatile);
1303}
1304
1305void CIRGenFunction::emitAtomicStore(RValue rvalue, LValue dest, bool isInit) {
1306 bool isVolatile = dest.isVolatileQualified();
1307 auto order = cir::MemOrder::SequentiallyConsistent;
1308 if (!dest.getType()->isAtomicType()) {
1310 }
1311 return emitAtomicStore(rvalue, dest, order, isVolatile, isInit);
1312}
1313
1314/// Emit a store to an l-value of atomic type.
1315///
1316/// Note that the r-value is expected to be an r-value of the atomic type; this
1317/// means that for aggregate r-values, it should include storage for any padding
1318/// that was necessary.
1320 cir::MemOrder order, bool isVolatile,
1321 bool isInit) {
1322 // If this is an aggregate r-value, it should agree in type except
1323 // maybe for address-space qualification.
1324 mlir::Location loc = dest.getPointer().getLoc();
1325 assert(!rvalue.isAggregate() ||
1327 dest.getAddress().getElementType());
1328
1329 AtomicInfo atomics(*this, dest, loc);
1330 LValue lvalue = atomics.getAtomicLValue();
1331
1332 if (lvalue.isSimple()) {
1333 // If this is an initialization, just put the value there normally.
1334 if (isInit) {
1335 atomics.emitCopyIntoMemory(rvalue);
1336 return;
1337 }
1338
1339 // Check whether we should use a library call.
1340 if (atomics.shouldUseLibCall()) {
1342 cgm.errorNYI(loc, "emitAtomicStore: atomic store with library call");
1343 return;
1344 }
1345
1346 // Okay, we're doing this natively.
1347 mlir::Value valueToStore = atomics.convertRValueToInt(rvalue);
1348
1349 // Do the atomic store.
1350 Address addr = atomics.getAtomicAddress();
1351 if (mlir::Value value = atomics.getScalarRValValueOrNull(rvalue)) {
1352 if (shouldCastToInt(value.getType(), /*CmpXchg=*/false)) {
1353 addr = atomics.castToAtomicIntPointer(addr);
1354 valueToStore =
1355 builder.createIntCast(valueToStore, addr.getElementType());
1356 }
1357 }
1358 cir::StoreOp store = builder.createStore(loc, valueToStore, addr);
1359
1360 // Initializations don't need to be atomic.
1361 if (!isInit) {
1363 store.setMemOrder(order);
1364 }
1365
1366 // Other decoration.
1367 if (isVolatile)
1368 store.setIsVolatile(true);
1369
1371 return;
1372 }
1373
1374 cgm.errorNYI(loc, "emitAtomicStore: non-simple atomic lvalue");
1376}
1377
1379 AtomicInfo atomics(*this, dest, getLoc(init->getSourceRange()));
1380
1381 switch (atomics.getEvaluationKind()) {
1382 case cir::TEK_Scalar: {
1383 mlir::Value value = emitScalarExpr(init);
1384 atomics.emitCopyIntoMemory(RValue::get(value));
1385 return;
1386 }
1387
1388 case cir::TEK_Complex: {
1389 mlir::Value value = emitComplexExpr(init);
1390 atomics.emitCopyIntoMemory(RValue::get(value));
1391 return;
1392 }
1393
1394 case cir::TEK_Aggregate: {
1395 // Fix up the destination if the initializer isn't an expression
1396 // of atomic type.
1397 bool zeroed = false;
1398 if (!init->getType()->isAtomicType()) {
1399 zeroed = atomics.emitMemSetZeroIfNecessary();
1400 dest = atomics.projectValue();
1401 }
1402
1403 // Evaluate the expression directly into the destination.
1409
1410 emitAggExpr(init, slot);
1411 return;
1412 }
1413 }
1414
1415 llvm_unreachable("bad evaluation kind");
1416}
static bool shouldCastToInt(mlir::Type valueTy, bool cmpxchg)
Return true if.
static Address emitValToTemp(CIRGenFunction &cgf, Expr *e)
static void emitAtomicCmpXchgFailureSetCheckWeak(CIRGenFunction &cgf, AtomicExpr *e, Expr *isWeakExpr, Address dest, Address ptr, Address val1, Address val2, Expr *failureOrderExpr, uint64_t size, cir::MemOrder successOrder, cir::SyncScopeKind scope)
static void emitAtomicCmpXchg(CIRGenFunction &cgf, AtomicExpr *e, bool isWeak, Address dest, Address ptr, Address val1, Address val2, uint64_t size, cir::MemOrder successOrder, cir::MemOrder failureOrder, cir::SyncScopeKind scope)
static void emitMemOrderCaseLabel(CIRGenBuilderTy &builder, mlir::Location loc, mlir::Type orderType, llvm::ArrayRef< cir::MemOrder > orders)
static cir::SyncScopeKind convertSyncScopeToCIR(CIRGenFunction &cgf, SourceRange range, clang::SyncScope scope)
static void emitAtomicExprWithDynamicMemOrder(CIRGenFunction &cgf, mlir::Value order, bool isStore, bool isLoad, bool isFence, llvm::function_ref< void(cir::MemOrder)> emitAtomicOpFn)
static void emitAtomicOp(CIRGenFunction &cgf, AtomicExpr *expr, Address dest, Address ptr, Address val1, Address val2, Expr *isWeakExpr, Expr *failureOrderExpr, int64_t size, cir::MemOrder order, cir::SyncScopeKind scope)
static void emitDefaultCaseLabel(CIRGenBuilderTy &builder, mlir::Location loc)
static bool isFullSizeType(CIRGenModule &cgm, mlir::Type ty, uint64_t expectedSize)
Does a store of the given IR type modify the full expected width?
static std::optional< cir::MemOrder > getEffectiveAtomicMemOrder(cir::MemOrder oriOrder, bool isStore, bool isLoad, bool isFence)
static void emitAtomicCmpXchgFailureSet(CIRGenFunction &cgf, AtomicExpr *e, bool isWeak, Address dest, Address ptr, Address val1, Address val2, Expr *failureOrderExpr, uint64_t size, cir::MemOrder successOrder, cir::SyncScopeKind scope)
*collection of selector each with an associated kind and an ordered *collection of selectors A selector has a kind
__device__ __2f16 b
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:508
TypeInfo getTypeInfo(const Type *T) const
Get the size and alignment of the specified complete type in bits.
int64_t toBits(CharUnits CharSize) const
Convert a size in characters to a size in bits.
const TargetInfo & getTargetInfo() const
Definition ASTContext.h:925
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:6928
static std::unique_ptr< AtomicScopeModel > getScopeModel(AtomicOp Op)
Get atomic scope model for the atomic op code.
Definition Expr.h:7077
Expr * getVal2() const
Definition Expr.h:6979
Expr * getOrder() const
Definition Expr.h:6962
Expr * getScope() const
Definition Expr.h:6965
bool isCmpXChg() const
Definition Expr.h:7012
AtomicOp getOp() const
Definition Expr.h:6991
Expr * getVal1() const
Definition Expr.h:6969
Expr * getPtr() const
Definition Expr.h:6959
Expr * getWeak() const
Definition Expr.h:6985
Expr * getOrderFail() const
Definition Expr.h:6975
bool isVolatile() const
Definition Expr.h:7008
Address withPointer(mlir::Value newPtr) const
Return address with different pointer, but same element type and alignment.
Definition Address.h:83
mlir::Value getPointer() const
Definition Address.h:98
mlir::Type getElementType() const
Definition Address.h:125
static Address invalid()
Definition Address.h:76
Address withElementType(CIRGenBuilderTy &builder, mlir::Type ElemTy) const
Return address with different element type, a bitcast pointer, and the same alignment.
clang::CharUnits getAlignment() const
Definition Address.h:138
bool isValid() const
Definition Address.h:77
An aggregate value slot.
static AggValueSlot forLValue(const LValue &LV, IsDestructed_t isDestructed, IsAliased_t isAliased, Overlap_t mayOverlap, IsZeroed_t isZeroed=IsNotZeroed)
cir::StoreOp createStore(mlir::Location loc, mlir::Value val, Address dst, bool isVolatile=false, mlir::IntegerAttr align={}, cir::SyncScopeKindAttr scope={}, cir::MemOrderAttr order={})
cir::LoadOp createLoad(mlir::Location loc, Address addr, bool isVolatile=false)
cir::IntType getUIntNTy(int n)
RValue convertTempToRValue(Address addr, clang::QualType type, clang::SourceLocation loc)
Given the address of a temporary variable, produce an r-value of its type.
Address emitPointerWithAlignment(const clang::Expr *expr, LValueBaseInfo *baseInfo=nullptr)
Given an expression with a pointer type, emit the value and compute our best estimate of the alignmen...
mlir::Value emitComplexExpr(const Expr *e)
Emit the computation of the specified expression of complex type, returning the result.
mlir::Location getLoc(clang::SourceLocation srcLoc)
Helpers to convert Clang's SourceLocation to a MLIR Location.
void emitAnyExprToMem(const Expr *e, Address location, Qualifiers quals, bool isInitializer)
Emits the code necessary to evaluate an arbitrary expression into the given memory location.
RValue emitAtomicExpr(AtomicExpr *e)
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)
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.
const cir::CIRDataLayout getDataLayout() const
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
CharUnits - This is an opaque type for sizes expressed in character units.
Definition CharUnits.h:38
llvm::Align getAsAlign() const
getAsAlign - Returns Quantity as a valid llvm::Align, Beware llvm::Align assumes power of two 8-bit b...
Definition CharUnits.h:189
QuantityType getQuantity() const
getQuantity - Get the raw integer representation of this quantity.
Definition CharUnits.h:185
This represents one expression.
Definition Expr.h:112
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:282
QualType getType() const
Definition Expr.h:144
A (possibly-)qualified type.
Definition TypeBase.h:937
Qualifiers getQualifiers() const
Retrieve the set of qualifiers applied to this type.
Definition TypeBase.h:8485
QualType getUnqualifiedType() const
Retrieve the unqualified variant of the given type, removing as little sugar as possible.
Definition TypeBase.h:8539
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:865
bool isVoidType() const
Definition TypeBase.h:9048
bool isPointerType() const
Definition TypeBase.h:8682
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
Definition Type.cpp:789
bool isAtomicType() const
Definition TypeBase.h:8874
const T * getAs() const
Member-template getAs<specific type>'.
Definition TypeBase.h:9275
bool isValidCIRAtomicOrderingCABI(Int value)
const internal::VariadicDynCastAllOfMatcher< Stmt, Expr > expr
Matches expressions.
@ Address
A pointer to a ValueDecl.
Definition Primitives.h:28
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
Definition Address.h:330
SyncScope
Defines sync scope values used internally by clang.
Definition SyncScope.h:42
unsigned long uint64_t
static bool atomicInfoGetAtomicPointer()
static bool aggValueSlotGC()
static bool opLoadStoreAtomic()
static bool opLoadStoreTbaa()
static bool atomicUseLibCall()
static bool atomicOpenMP()
static bool atomicMicrosoftVolatile()
static bool atomicSyncScopeID()
static bool atomicInfoGetAtomicAddress()
EvalResult is a struct with detailed info about an evaluated expression.
Definition Expr.h:648
APValue Val
Val - This is the value the expression can be folded to.
Definition Expr.h:650