Skip to content

Commit 4d4c30a

Browse files
authored
Use Address for CGBuilder's CreateAtomicRMW and CreateAtomicCmpXchg. (#74349)
Update all callers to pass through the Address. For the older builtins such as `__sync_*` and MSVC `_Interlocked*`, natural alignment of the atomic access is _assumed_. This change preserves that behavior. It will pass through greater-than-required alignments, however.
1 parent a0eda10 commit 4d4c30a

File tree

9 files changed

+198
-95
lines changed

9 files changed

+198
-95
lines changed

clang/lib/CodeGen/CGAtomic.cpp

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -383,8 +383,7 @@ static void emitAtomicCmpXchg(CodeGenFunction &CGF, AtomicExpr *E, bool IsWeak,
383383
llvm::Value *Desired = CGF.Builder.CreateLoad(Val2);
384384

385385
llvm::AtomicCmpXchgInst *Pair = CGF.Builder.CreateAtomicCmpXchg(
386-
Ptr.getPointer(), Expected, Desired, SuccessOrder, FailureOrder,
387-
Scope);
386+
Ptr, Expected, Desired, SuccessOrder, FailureOrder, Scope);
388387
Pair->setVolatile(E->isVolatile());
389388
Pair->setWeak(IsWeak);
390389

@@ -699,7 +698,7 @@ static void EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *E, Address Dest,
699698

700699
llvm::Value *LoadVal1 = CGF.Builder.CreateLoad(Val1);
701700
llvm::AtomicRMWInst *RMWI =
702-
CGF.Builder.CreateAtomicRMW(Op, Ptr.getPointer(), LoadVal1, Order, Scope);
701+
CGF.Builder.CreateAtomicRMW(Op, Ptr, LoadVal1, Order, Scope);
703702
RMWI->setVolatile(E->isVolatile());
704703

705704
// For __atomic_*_fetch operations, perform the operation again to
@@ -1740,8 +1739,7 @@ std::pair<llvm::Value *, llvm::Value *> AtomicInfo::EmitAtomicCompareExchangeOp(
17401739
llvm::AtomicOrdering Success, llvm::AtomicOrdering Failure, bool IsWeak) {
17411740
// Do the atomic store.
17421741
Address Addr = getAtomicAddressAsAtomicIntPointer();
1743-
auto *Inst = CGF.Builder.CreateAtomicCmpXchg(Addr.getPointer(),
1744-
ExpectedVal, DesiredVal,
1742+
auto *Inst = CGF.Builder.CreateAtomicCmpXchg(Addr, ExpectedVal, DesiredVal,
17451743
Success, Failure);
17461744
// Other decoration.
17471745
Inst->setVolatile(LVal.isVolatileQualified());

clang/lib/CodeGen/CGBuilder.h

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -126,25 +126,22 @@ class CGBuilderTy : public CGBuilderBaseTy {
126126
return CreateAlignedStore(getInt1(Value), Addr, CharUnits::One());
127127
}
128128

129-
// Temporarily use old signature; clang will be updated to an Address overload
130-
// in a subsequent patch.
131129
llvm::AtomicCmpXchgInst *
132-
CreateAtomicCmpXchg(llvm::Value *Ptr, llvm::Value *Cmp, llvm::Value *New,
130+
CreateAtomicCmpXchg(Address Addr, llvm::Value *Cmp, llvm::Value *New,
133131
llvm::AtomicOrdering SuccessOrdering,
134132
llvm::AtomicOrdering FailureOrdering,
135133
llvm::SyncScope::ID SSID = llvm::SyncScope::System) {
136134
return CGBuilderBaseTy::CreateAtomicCmpXchg(
137-
Ptr, Cmp, New, llvm::MaybeAlign(), SuccessOrdering, FailureOrdering,
138-
SSID);
135+
Addr.getPointer(), Cmp, New, Addr.getAlignment().getAsAlign(),
136+
SuccessOrdering, FailureOrdering, SSID);
139137
}
140138

141-
// Temporarily use old signature; clang will be updated to an Address overload
142-
// in a subsequent patch.
143139
llvm::AtomicRMWInst *
144-
CreateAtomicRMW(llvm::AtomicRMWInst::BinOp Op, llvm::Value *Ptr,
145-
llvm::Value *Val, llvm::AtomicOrdering Ordering,
140+
CreateAtomicRMW(llvm::AtomicRMWInst::BinOp Op, Address Addr, llvm::Value *Val,
141+
llvm::AtomicOrdering Ordering,
146142
llvm::SyncScope::ID SSID = llvm::SyncScope::System) {
147-
return CGBuilderBaseTy::CreateAtomicRMW(Op, Ptr, Val, llvm::MaybeAlign(),
143+
return CGBuilderBaseTy::CreateAtomicRMW(Op, Addr.getPointer(), Val,
144+
Addr.getAlignment().getAsAlign(),
148145
Ordering, SSID);
149146
}
150147

clang/lib/CodeGen/CGBuiltin.cpp

Lines changed: 67 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -188,8 +188,7 @@ static Value *EmitFromInt(CodeGenFunction &CGF, llvm::Value *V,
188188
return V;
189189
}
190190

191-
static llvm::Value *CheckAtomicAlignment(CodeGenFunction &CGF,
192-
const CallExpr *E) {
191+
static Address CheckAtomicAlignment(CodeGenFunction &CGF, const CallExpr *E) {
193192
ASTContext &Ctx = CGF.getContext();
194193
Address Ptr = CGF.EmitPointerWithAlignment(E->getArg(0));
195194
unsigned Bytes = Ptr.getElementType()->isPointerTy()
@@ -199,8 +198,10 @@ static llvm::Value *CheckAtomicAlignment(CodeGenFunction &CGF,
199198
if (Align % Bytes != 0) {
200199
DiagnosticsEngine &Diags = CGF.CGM.getDiags();
201200
Diags.Report(E->getBeginLoc(), diag::warn_sync_op_misaligned);
201+
// Force address to be at least naturally-aligned.
202+
return Ptr.withAlignment(CharUnits::fromQuantity(Bytes));
202203
}
203-
return Ptr.getPointer();
204+
return Ptr;
204205
}
205206

206207
/// Utility to insert an atomic instruction based on Intrinsic::ID
@@ -215,19 +216,17 @@ static Value *MakeBinaryAtomicValue(
215216
E->getArg(0)->getType()->getPointeeType()));
216217
assert(CGF.getContext().hasSameUnqualifiedType(T, E->getArg(1)->getType()));
217218

218-
llvm::Value *DestPtr = CheckAtomicAlignment(CGF, E);
219+
Address DestAddr = CheckAtomicAlignment(CGF, E);
219220

220221
llvm::IntegerType *IntType = llvm::IntegerType::get(
221222
CGF.getLLVMContext(), CGF.getContext().getTypeSize(T));
222223

223-
llvm::Value *Args[2];
224-
Args[0] = DestPtr;
225-
Args[1] = CGF.EmitScalarExpr(E->getArg(1));
226-
llvm::Type *ValueType = Args[1]->getType();
227-
Args[1] = EmitToInt(CGF, Args[1], T, IntType);
224+
llvm::Value *Val = CGF.EmitScalarExpr(E->getArg(1));
225+
llvm::Type *ValueType = Val->getType();
226+
Val = EmitToInt(CGF, Val, T, IntType);
228227

229-
llvm::Value *Result = CGF.Builder.CreateAtomicRMW(
230-
Kind, Args[0], Args[1], Ordering);
228+
llvm::Value *Result =
229+
CGF.Builder.CreateAtomicRMW(Kind, DestAddr, Val, Ordering);
231230
return EmitFromInt(CGF, Result, T, ValueType);
232231
}
233232

@@ -270,20 +269,18 @@ static RValue EmitBinaryAtomicPost(CodeGenFunction &CGF,
270269
E->getArg(0)->getType()->getPointeeType()));
271270
assert(CGF.getContext().hasSameUnqualifiedType(T, E->getArg(1)->getType()));
272271

273-
llvm::Value *DestPtr = CheckAtomicAlignment(CGF, E);
272+
Address DestAddr = CheckAtomicAlignment(CGF, E);
274273

275274
llvm::IntegerType *IntType = llvm::IntegerType::get(
276275
CGF.getLLVMContext(), CGF.getContext().getTypeSize(T));
277276

278-
llvm::Value *Args[2];
279-
Args[1] = CGF.EmitScalarExpr(E->getArg(1));
280-
llvm::Type *ValueType = Args[1]->getType();
281-
Args[1] = EmitToInt(CGF, Args[1], T, IntType);
282-
Args[0] = DestPtr;
277+
llvm::Value *Val = CGF.EmitScalarExpr(E->getArg(1));
278+
llvm::Type *ValueType = Val->getType();
279+
Val = EmitToInt(CGF, Val, T, IntType);
283280

284281
llvm::Value *Result = CGF.Builder.CreateAtomicRMW(
285-
Kind, Args[0], Args[1], llvm::AtomicOrdering::SequentiallyConsistent);
286-
Result = CGF.Builder.CreateBinOp(Op, Result, Args[1]);
282+
Kind, DestAddr, Val, llvm::AtomicOrdering::SequentiallyConsistent);
283+
Result = CGF.Builder.CreateBinOp(Op, Result, Val);
287284
if (Invert)
288285
Result =
289286
CGF.Builder.CreateBinOp(llvm::Instruction::Xor, Result,
@@ -309,20 +306,18 @@ static RValue EmitBinaryAtomicPost(CodeGenFunction &CGF,
309306
static Value *MakeAtomicCmpXchgValue(CodeGenFunction &CGF, const CallExpr *E,
310307
bool ReturnBool) {
311308
QualType T = ReturnBool ? E->getArg(1)->getType() : E->getType();
312-
llvm::Value *DestPtr = CheckAtomicAlignment(CGF, E);
309+
Address DestAddr = CheckAtomicAlignment(CGF, E);
313310

314311
llvm::IntegerType *IntType = llvm::IntegerType::get(
315312
CGF.getLLVMContext(), CGF.getContext().getTypeSize(T));
316313

317-
Value *Args[3];
318-
Args[0] = DestPtr;
319-
Args[1] = CGF.EmitScalarExpr(E->getArg(1));
320-
llvm::Type *ValueType = Args[1]->getType();
321-
Args[1] = EmitToInt(CGF, Args[1], T, IntType);
322-
Args[2] = EmitToInt(CGF, CGF.EmitScalarExpr(E->getArg(2)), T, IntType);
314+
Value *Cmp = CGF.EmitScalarExpr(E->getArg(1));
315+
llvm::Type *ValueType = Cmp->getType();
316+
Cmp = EmitToInt(CGF, Cmp, T, IntType);
317+
Value *New = EmitToInt(CGF, CGF.EmitScalarExpr(E->getArg(2)), T, IntType);
323318

324319
Value *Pair = CGF.Builder.CreateAtomicCmpXchg(
325-
Args[0], Args[1], Args[2], llvm::AtomicOrdering::SequentiallyConsistent,
320+
DestAddr, Cmp, New, llvm::AtomicOrdering::SequentiallyConsistent,
326321
llvm::AtomicOrdering::SequentiallyConsistent);
327322
if (ReturnBool)
328323
// Extract boolean success flag and zext it to int.
@@ -358,7 +353,8 @@ Value *EmitAtomicCmpXchgForMSIntrin(CodeGenFunction &CGF, const CallExpr *E,
358353
assert(CGF.getContext().hasSameUnqualifiedType(E->getType(),
359354
E->getArg(2)->getType()));
360355

361-
auto *Destination = CGF.EmitScalarExpr(E->getArg(0));
356+
Address DestAddr = CheckAtomicAlignment(CGF, E);
357+
362358
auto *Comparand = CGF.EmitScalarExpr(E->getArg(2));
363359
auto *Exchange = CGF.EmitScalarExpr(E->getArg(1));
364360

@@ -372,8 +368,7 @@ Value *EmitAtomicCmpXchgForMSIntrin(CodeGenFunction &CGF, const CallExpr *E,
372368
// _Interlocked* operations in the future, we will have to remove the volatile
373369
// marker.
374370
auto *Result = CGF.Builder.CreateAtomicCmpXchg(
375-
Destination, Comparand, Exchange,
376-
SuccessOrdering, FailureOrdering);
371+
DestAddr, Comparand, Exchange, SuccessOrdering, FailureOrdering);
377372
Result->setVolatile(true);
378373
return CGF.Builder.CreateExtractValue(Result, 0);
379374
}
@@ -386,29 +381,34 @@ Value *EmitAtomicCmpXchgForMSIntrin(CodeGenFunction &CGF, const CallExpr *E,
386381
// __int64 _ExchangeHigh,
387382
// __int64 _ExchangeLow,
388383
// __int64 * _ComparandResult);
384+
//
385+
// Note that Destination is assumed to be at least 16-byte aligned, despite
386+
// being typed int64.
387+
389388
static Value *EmitAtomicCmpXchg128ForMSIntrin(CodeGenFunction &CGF,
390389
const CallExpr *E,
391390
AtomicOrdering SuccessOrdering) {
392391
assert(E->getNumArgs() == 4);
393-
llvm::Value *Destination = CGF.EmitScalarExpr(E->getArg(0));
392+
llvm::Value *DestPtr = CGF.EmitScalarExpr(E->getArg(0));
394393
llvm::Value *ExchangeHigh = CGF.EmitScalarExpr(E->getArg(1));
395394
llvm::Value *ExchangeLow = CGF.EmitScalarExpr(E->getArg(2));
396-
llvm::Value *ComparandPtr = CGF.EmitScalarExpr(E->getArg(3));
395+
Address ComparandAddr = CGF.EmitPointerWithAlignment(E->getArg(3));
397396

398-
assert(Destination->getType()->isPointerTy());
397+
assert(DestPtr->getType()->isPointerTy());
399398
assert(!ExchangeHigh->getType()->isPointerTy());
400399
assert(!ExchangeLow->getType()->isPointerTy());
401-
assert(ComparandPtr->getType()->isPointerTy());
402400

403401
// For Release ordering, the failure ordering should be Monotonic.
404402
auto FailureOrdering = SuccessOrdering == AtomicOrdering::Release
405403
? AtomicOrdering::Monotonic
406404
: SuccessOrdering;
407405

408-
// Convert to i128 pointers and values.
406+
// Convert to i128 pointers and values. Alignment is also overridden for
407+
// destination pointer.
409408
llvm::Type *Int128Ty = llvm::IntegerType::get(CGF.getLLVMContext(), 128);
410-
Address ComparandResult(ComparandPtr, Int128Ty,
411-
CGF.getContext().toCharUnitsFromBits(128));
409+
Address DestAddr(DestPtr, Int128Ty,
410+
CGF.getContext().toCharUnitsFromBits(128));
411+
ComparandAddr = ComparandAddr.withElementType(Int128Ty);
412412

413413
// (((i128)hi) << 64) | ((i128)lo)
414414
ExchangeHigh = CGF.Builder.CreateZExt(ExchangeHigh, Int128Ty);
@@ -418,9 +418,9 @@ static Value *EmitAtomicCmpXchg128ForMSIntrin(CodeGenFunction &CGF,
418418
llvm::Value *Exchange = CGF.Builder.CreateOr(ExchangeHigh, ExchangeLow);
419419

420420
// Load the comparand for the instruction.
421-
llvm::Value *Comparand = CGF.Builder.CreateLoad(ComparandResult);
421+
llvm::Value *Comparand = CGF.Builder.CreateLoad(ComparandAddr);
422422

423-
auto *CXI = CGF.Builder.CreateAtomicCmpXchg(Destination, Comparand, Exchange,
423+
auto *CXI = CGF.Builder.CreateAtomicCmpXchg(DestAddr, Comparand, Exchange,
424424
SuccessOrdering, FailureOrdering);
425425

426426
// The atomic instruction is marked volatile for consistency with MSVC. This
@@ -431,7 +431,7 @@ static Value *EmitAtomicCmpXchg128ForMSIntrin(CodeGenFunction &CGF,
431431

432432
// Store the result as an outparameter.
433433
CGF.Builder.CreateStore(CGF.Builder.CreateExtractValue(CXI, 0),
434-
ComparandResult);
434+
ComparandAddr);
435435

436436
// Get the success boolean and zero extend it to i8.
437437
Value *Success = CGF.Builder.CreateExtractValue(CXI, 1);
@@ -443,24 +443,21 @@ static Value *EmitAtomicIncrementValue(CodeGenFunction &CGF, const CallExpr *E,
443443
assert(E->getArg(0)->getType()->isPointerType());
444444

445445
auto *IntTy = CGF.ConvertType(E->getType());
446+
Address DestAddr = CheckAtomicAlignment(CGF, E);
446447
auto *Result = CGF.Builder.CreateAtomicRMW(
447-
AtomicRMWInst::Add,
448-
CGF.EmitScalarExpr(E->getArg(0)),
449-
ConstantInt::get(IntTy, 1),
450-
Ordering);
448+
AtomicRMWInst::Add, DestAddr, ConstantInt::get(IntTy, 1), Ordering);
451449
return CGF.Builder.CreateAdd(Result, ConstantInt::get(IntTy, 1));
452450
}
453451

454-
static Value *EmitAtomicDecrementValue(CodeGenFunction &CGF, const CallExpr *E,
452+
static Value *EmitAtomicDecrementValue(
453+
CodeGenFunction &CGF, const CallExpr *E,
455454
AtomicOrdering Ordering = AtomicOrdering::SequentiallyConsistent) {
456455
assert(E->getArg(0)->getType()->isPointerType());
457456

458457
auto *IntTy = CGF.ConvertType(E->getType());
458+
Address DestAddr = CheckAtomicAlignment(CGF, E);
459459
auto *Result = CGF.Builder.CreateAtomicRMW(
460-
AtomicRMWInst::Sub,
461-
CGF.EmitScalarExpr(E->getArg(0)),
462-
ConstantInt::get(IntTy, 1),
463-
Ordering);
460+
AtomicRMWInst::Sub, DestAddr, ConstantInt::get(IntTy, 1), Ordering);
464461
return CGF.Builder.CreateSub(Result, ConstantInt::get(IntTy, 1));
465462
}
466463

@@ -1215,8 +1212,7 @@ static llvm::Value *EmitBitTestIntrinsic(CodeGenFunction &CGF,
12151212
Mask = CGF.Builder.CreateNot(Mask);
12161213
RMWOp = llvm::AtomicRMWInst::And;
12171214
}
1218-
OldByte = CGF.Builder.CreateAtomicRMW(RMWOp, ByteAddr.getPointer(), Mask,
1219-
Ordering);
1215+
OldByte = CGF.Builder.CreateAtomicRMW(RMWOp, ByteAddr, Mask, Ordering);
12201216
} else {
12211217
// Emit a plain load for the non-interlocked intrinsics.
12221218
OldByte = CGF.Builder.CreateLoad(ByteAddr, "bittest.byte");
@@ -4456,14 +4452,13 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
44564452
case Builtin::BI__sync_lock_release_4:
44574453
case Builtin::BI__sync_lock_release_8:
44584454
case Builtin::BI__sync_lock_release_16: {
4459-
Value *Ptr = CheckAtomicAlignment(*this, E);
4455+
Address Ptr = CheckAtomicAlignment(*this, E);
44604456
QualType ElTy = E->getArg(0)->getType()->getPointeeType();
4461-
CharUnits StoreSize = getContext().getTypeSizeInChars(ElTy);
4462-
llvm::Type *ITy =
4463-
llvm::IntegerType::get(getLLVMContext(), StoreSize.getQuantity() * 8);
4457+
4458+
llvm::Type *ITy = llvm::IntegerType::get(getLLVMContext(),
4459+
getContext().getTypeSize(ElTy));
44644460
llvm::StoreInst *Store =
4465-
Builder.CreateAlignedStore(llvm::Constant::getNullValue(ITy), Ptr,
4466-
StoreSize);
4461+
Builder.CreateStore(llvm::Constant::getNullValue(ITy), Ptr);
44674462
Store->setAtomic(llvm::AtomicOrdering::Release);
44684463
return RValue::get(nullptr);
44694464
}
@@ -4514,7 +4509,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
45144509
bool Volatile =
45154510
PtrTy->castAs<PointerType>()->getPointeeType().isVolatileQualified();
45164511

4517-
Value *Ptr = EmitScalarExpr(E->getArg(0));
4512+
Address Ptr =
4513+
EmitPointerWithAlignment(E->getArg(0)).withElementType(Int8Ty);
4514+
45184515
Value *NewVal = Builder.getInt8(1);
45194516
Value *Order = EmitScalarExpr(E->getArg(1));
45204517
if (isa<llvm::ConstantInt>(Order)) {
@@ -5035,7 +5032,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
50355032
llvm::IntegerType *IntType = IntegerType::get(
50365033
getLLVMContext(), getContext().getTypeSize(E->getType()));
50375034

5038-
llvm::Value *Destination = EmitScalarExpr(E->getArg(0));
5035+
Address DestAddr = CheckAtomicAlignment(*this, E);
50395036

50405037
llvm::Value *Exchange = EmitScalarExpr(E->getArg(1));
50415038
RTy = Exchange->getType();
@@ -5048,7 +5045,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
50485045
BuiltinID == Builtin::BI_InterlockedCompareExchangePointer_nf ?
50495046
AtomicOrdering::Monotonic : AtomicOrdering::SequentiallyConsistent;
50505047

5051-
auto Result = Builder.CreateAtomicCmpXchg(Destination, Comparand, Exchange,
5048+
auto Result = Builder.CreateAtomicCmpXchg(DestAddr, Comparand, Exchange,
50525049
Ordering, Ordering);
50535050
Result->setVolatile(true);
50545051

@@ -11901,12 +11898,12 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
1190111898
}
1190211899

1190311900
case clang::AArch64::BI_InterlockedAdd: {
11904-
Value *Arg0 = EmitScalarExpr(E->getArg(0));
11905-
Value *Arg1 = EmitScalarExpr(E->getArg(1));
11906-
AtomicRMWInst *RMWI = Builder.CreateAtomicRMW(
11907-
AtomicRMWInst::Add, Arg0, Arg1,
11908-
llvm::AtomicOrdering::SequentiallyConsistent);
11909-
return Builder.CreateAdd(RMWI, Arg1);
11901+
Address DestAddr = CheckAtomicAlignment(*this, E);
11902+
Value *Val = EmitScalarExpr(E->getArg(1));
11903+
AtomicRMWInst *RMWI =
11904+
Builder.CreateAtomicRMW(AtomicRMWInst::Add, DestAddr, Val,
11905+
llvm::AtomicOrdering::SequentiallyConsistent);
11906+
return Builder.CreateAdd(RMWI, Val);
1191011907
}
1191111908
}
1191211909

@@ -18219,7 +18216,7 @@ Value *CodeGenFunction::EmitAMDGPUBuiltinExpr(unsigned BuiltinID,
1821918216
break;
1822018217
}
1822118218

18222-
Value *Ptr = EmitScalarExpr(E->getArg(0));
18219+
Address Ptr = CheckAtomicAlignment(*this, E);
1822318220
Value *Val = EmitScalarExpr(E->getArg(1));
1822418221

1822518222
ProcessOrderScopeAMDGCN(EmitScalarExpr(E->getArg(2)),
@@ -19108,9 +19105,10 @@ Value *CodeGenFunction::EmitNVPTXBuiltinExpr(unsigned BuiltinID,
1910819105

1910919106
case NVPTX::BI__nvvm_atom_add_gen_f:
1911019107
case NVPTX::BI__nvvm_atom_add_gen_d: {
19111-
Value *Ptr = EmitScalarExpr(E->getArg(0));
19108+
Address DestAddr = EmitPointerWithAlignment(E->getArg(0));
1911219109
Value *Val = EmitScalarExpr(E->getArg(1));
19113-
return Builder.CreateAtomicRMW(llvm::AtomicRMWInst::FAdd, Ptr, Val,
19110+
19111+
return Builder.CreateAtomicRMW(llvm::AtomicRMWInst::FAdd, DestAddr, Val,
1911419112
AtomicOrdering::SequentiallyConsistent);
1911519113
}
1911619114

0 commit comments

Comments
 (0)