Skip to content

[SROA] Use !tbaa instead of !tbaa.struct if op matches field. #81289

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 13 commits into from
Feb 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 14 additions & 7 deletions clang/test/CodeGen/aarch64-ABI-align-packed.c
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ struct non_packed_struct gs_non_packed_struct;
// CHECK-NEXT: entry:
// CHECK-NEXT: [[S_NON_PACKED_STRUCT_COERCE_FCA_0_EXTRACT:%.*]] = extractvalue [1 x <8 x i16>] [[S_NON_PACKED_STRUCT_COERCE]], 0
// CHECK-NEXT: store double [[D8]], ptr @gd, align 8, !tbaa [[TBAA2:![0-9]+]]
// CHECK-NEXT: store <8 x i16> [[S_NON_PACKED_STRUCT_COERCE_FCA_0_EXTRACT]], ptr @gs_non_packed_struct, align 16, !tbaa.struct [[TBAA_STRUCT6:![0-9]+]]
// CHECK-NEXT: store <8 x i16> [[S_NON_PACKED_STRUCT_COERCE_FCA_0_EXTRACT]], ptr @gs_non_packed_struct, align 16, !tbaa [[TBAA6:![0-9]+]]
// CHECK-NEXT: ret void
__attribute__((noinline)) void named_arg_non_packed_struct(double d0, double d1, double d2, double d3,
double d4, double d5, double d6, double d7,
Expand Down Expand Up @@ -114,7 +114,7 @@ struct packed_struct gs_packed_struct;
// CHECK-NEXT: entry:
// CHECK-NEXT: [[S_PACKED_STRUCT_COERCE_FCA_0_EXTRACT:%.*]] = extractvalue [1 x <8 x i16>] [[S_PACKED_STRUCT_COERCE]], 0
// CHECK-NEXT: store double [[D8]], ptr @gd, align 8, !tbaa [[TBAA2]]
// CHECK-NEXT: store <8 x i16> [[S_PACKED_STRUCT_COERCE_FCA_0_EXTRACT]], ptr @gs_packed_struct, align 1, !tbaa.struct [[TBAA_STRUCT6]]
// CHECK-NEXT: store <8 x i16> [[S_PACKED_STRUCT_COERCE_FCA_0_EXTRACT]], ptr @gs_packed_struct, align 1, !tbaa [[TBAA6]]
// CHECK-NEXT: ret void
__attribute__((noinline)) void named_arg_packed_struct(double d0, double d1, double d2, double d3,
double d4, double d5, double d6, double d7,
Expand Down Expand Up @@ -169,7 +169,7 @@ struct packed_member gs_packed_member;
// CHECK-NEXT: entry:
// CHECK-NEXT: [[S_PACKED_MEMBER_COERCE_FCA_0_EXTRACT:%.*]] = extractvalue [1 x <8 x i16>] [[S_PACKED_MEMBER_COERCE]], 0
// CHECK-NEXT: store double [[D8]], ptr @gd, align 8, !tbaa [[TBAA2]]
// CHECK-NEXT: store <8 x i16> [[S_PACKED_MEMBER_COERCE_FCA_0_EXTRACT]], ptr @gs_packed_member, align 1, !tbaa.struct [[TBAA_STRUCT6]]
// CHECK-NEXT: store <8 x i16> [[S_PACKED_MEMBER_COERCE_FCA_0_EXTRACT]], ptr @gs_packed_member, align 1, !tbaa [[TBAA6]]
// CHECK-NEXT: ret void
__attribute__((noinline)) void named_arg_packed_member(double d0, double d1, double d2, double d3,
double d4, double d5, double d6, double d7,
Expand Down Expand Up @@ -224,7 +224,7 @@ struct aligned_struct_8 gs_aligned_struct_8;
// CHECK-NEXT: entry:
// CHECK-NEXT: [[S_ALIGNED_STRUCT_8_COERCE_FCA_0_EXTRACT:%.*]] = extractvalue [1 x <8 x i16>] [[S_ALIGNED_STRUCT_8_COERCE]], 0
// CHECK-NEXT: store double [[D8]], ptr @gd, align 8, !tbaa [[TBAA2]]
// CHECK-NEXT: store <8 x i16> [[S_ALIGNED_STRUCT_8_COERCE_FCA_0_EXTRACT]], ptr @gs_aligned_struct_8, align 16, !tbaa.struct [[TBAA_STRUCT6]]
// CHECK-NEXT: store <8 x i16> [[S_ALIGNED_STRUCT_8_COERCE_FCA_0_EXTRACT]], ptr @gs_aligned_struct_8, align 16, !tbaa [[TBAA6]]
// CHECK-NEXT: ret void
__attribute__((noinline)) void named_arg_aligned_struct_8(double d0, double d1, double d2, double d3,
double d4, double d5, double d6, double d7,
Expand Down Expand Up @@ -279,7 +279,7 @@ struct aligned_member_8 gs_aligned_member_8;
// CHECK-NEXT: entry:
// CHECK-NEXT: [[S_ALIGNED_MEMBER_8_COERCE_FCA_0_EXTRACT:%.*]] = extractvalue [1 x <8 x i16>] [[S_ALIGNED_MEMBER_8_COERCE]], 0
// CHECK-NEXT: store double [[D8]], ptr @gd, align 8, !tbaa [[TBAA2]]
// CHECK-NEXT: store <8 x i16> [[S_ALIGNED_MEMBER_8_COERCE_FCA_0_EXTRACT]], ptr @gs_aligned_member_8, align 16, !tbaa.struct [[TBAA_STRUCT6]]
// CHECK-NEXT: store <8 x i16> [[S_ALIGNED_MEMBER_8_COERCE_FCA_0_EXTRACT]], ptr @gs_aligned_member_8, align 16, !tbaa [[TBAA6]]
// CHECK-NEXT: ret void
__attribute__((noinline)) void named_arg_aligned_member_8(double d0, double d1, double d2, double d3,
double d4, double d5, double d6, double d7,
Expand Down Expand Up @@ -334,7 +334,7 @@ struct pragma_packed_struct_8 gs_pragma_packed_struct_8;
// CHECK-NEXT: entry:
// CHECK-NEXT: [[S_PRAGMA_PACKED_STRUCT_8_COERCE_FCA_0_EXTRACT:%.*]] = extractvalue [1 x <8 x i16>] [[S_PRAGMA_PACKED_STRUCT_8_COERCE]], 0
// CHECK-NEXT: store double [[D8]], ptr @gd, align 8, !tbaa [[TBAA2]]
// CHECK-NEXT: store <8 x i16> [[S_PRAGMA_PACKED_STRUCT_8_COERCE_FCA_0_EXTRACT]], ptr @gs_pragma_packed_struct_8, align 8, !tbaa.struct [[TBAA_STRUCT6]]
// CHECK-NEXT: store <8 x i16> [[S_PRAGMA_PACKED_STRUCT_8_COERCE_FCA_0_EXTRACT]], ptr @gs_pragma_packed_struct_8, align 8, !tbaa [[TBAA6]]
// CHECK-NEXT: ret void
__attribute__((noinline)) void named_arg_pragma_packed_struct_8(double d0, double d1, double d2, double d3,
double d4, double d5, double d6, double d7,
Expand Down Expand Up @@ -389,7 +389,7 @@ struct pragma_packed_struct_4 gs_pragma_packed_struct_4;
// CHECK-NEXT: entry:
// CHECK-NEXT: [[S_PRAGMA_PACKED_STRUCT_4_COERCE_FCA_0_EXTRACT:%.*]] = extractvalue [1 x <8 x i16>] [[S_PRAGMA_PACKED_STRUCT_4_COERCE]], 0
// CHECK-NEXT: store double [[D8]], ptr @gd, align 8, !tbaa [[TBAA2]]
// CHECK-NEXT: store <8 x i16> [[S_PRAGMA_PACKED_STRUCT_4_COERCE_FCA_0_EXTRACT]], ptr @gs_pragma_packed_struct_4, align 4, !tbaa.struct [[TBAA_STRUCT6]]
// CHECK-NEXT: store <8 x i16> [[S_PRAGMA_PACKED_STRUCT_4_COERCE_FCA_0_EXTRACT]], ptr @gs_pragma_packed_struct_4, align 4, !tbaa [[TBAA6]]
// CHECK-NEXT: ret void
__attribute__((noinline)) void named_arg_pragma_packed_struct_4(double d0, double d1, double d2, double d3,
double d4, double d5, double d6, double d7,
Expand Down Expand Up @@ -436,3 +436,10 @@ void test_pragma_packed_struct_4() {
named_arg_pragma_packed_struct_4(1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 2.0, s_pragma_packed_struct_4);
variadic_pragma_packed_struct_4(1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 2.0, s_pragma_packed_struct_4);
}
//.
// CHECK: [[TBAA2]] = !{[[META3:![0-9]+]], [[META3]], i64 0}
// CHECK: [[META3]] = !{!"double", [[META4:![0-9]+]], i64 0}
// CHECK: [[META4]] = !{!"omnipotent char", [[META5:![0-9]+]], i64 0}
// CHECK: [[META5]] = !{!"Simple C/C++ TBAA"}
// CHECK: [[TBAA6]] = !{[[META4]], [[META4]], i64 0}
//.
3 changes: 3 additions & 0 deletions llvm/include/llvm/IR/Metadata.h
Original file line number Diff line number Diff line change
Expand Up @@ -849,6 +849,9 @@ struct AAMDNodes {
/// If his AAMDNode has !tbaa.struct and \p AccessSize matches the size of the
/// field at offset 0, get the TBAA tag describing the accessed field.
AAMDNodes adjustForAccess(unsigned AccessSize);
AAMDNodes adjustForAccess(size_t Offset, Type *AccessTy,
const DataLayout &DL);
AAMDNodes adjustForAccess(size_t Offset, unsigned AccessSize);
};

// Specialize DenseMapInfo for AAMDNodes.
Expand Down
17 changes: 17 additions & 0 deletions llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -833,3 +833,20 @@ AAMDNodes AAMDNodes::adjustForAccess(unsigned AccessSize) {
}
return New;
}

AAMDNodes AAMDNodes::adjustForAccess(size_t Offset, Type *AccessTy,
const DataLayout &DL) {
AAMDNodes New = shift(Offset);
if (!DL.typeSizeEqualsStoreSize(AccessTy))
return New;
TypeSize Size = DL.getTypeStoreSize(AccessTy);
if (Size.isScalable())
return New;

return New.adjustForAccess(Size.getKnownMinValue());
}

AAMDNodes AAMDNodes::adjustForAccess(size_t Offset, unsigned AccessSize) {
AAMDNodes New = shift(Offset);
return New.adjustForAccess(AccessSize);
}
46 changes: 33 additions & 13 deletions llvm/lib/Transforms/Scalar/SROA.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2914,7 +2914,8 @@ class AllocaSliceRewriter : public InstVisitor<AllocaSliceRewriter, bool> {

// Do this after copyMetadataForLoad() to preserve the TBAA shift.
if (AATags)
NewLI->setAAMetadata(AATags.shift(NewBeginOffset - BeginOffset));
NewLI->setAAMetadata(AATags.adjustForAccess(
NewBeginOffset - BeginOffset, NewLI->getType(), DL));

// Try to preserve nonnull metadata
V = NewLI;
Expand All @@ -2935,8 +2936,11 @@ class AllocaSliceRewriter : public InstVisitor<AllocaSliceRewriter, bool> {
LoadInst *NewLI =
IRB.CreateAlignedLoad(TargetTy, getNewAllocaSlicePtr(IRB, LTy),
getSliceAlign(), LI.isVolatile(), LI.getName());

if (AATags)
NewLI->setAAMetadata(AATags.shift(NewBeginOffset - BeginOffset));
NewLI->setAAMetadata(AATags.adjustForAccess(
NewBeginOffset - BeginOffset, NewLI->getType(), DL));

if (LI.isVolatile())
NewLI->setAtomic(LI.getOrdering(), LI.getSyncScopeID());
NewLI->copyMetadata(LI, {LLVMContext::MD_mem_parallel_loop_access,
Expand Down Expand Up @@ -3011,7 +3015,8 @@ class AllocaSliceRewriter : public InstVisitor<AllocaSliceRewriter, bool> {
Store->copyMetadata(SI, {LLVMContext::MD_mem_parallel_loop_access,
LLVMContext::MD_access_group});
if (AATags)
Store->setAAMetadata(AATags.shift(NewBeginOffset - BeginOffset));
Store->setAAMetadata(AATags.adjustForAccess(NewBeginOffset - BeginOffset,
V->getType(), DL));
Pass.DeadInsts.push_back(&SI);

// NOTE: Careful to use OrigV rather than V.
Expand All @@ -3038,7 +3043,8 @@ class AllocaSliceRewriter : public InstVisitor<AllocaSliceRewriter, bool> {
Store->copyMetadata(SI, {LLVMContext::MD_mem_parallel_loop_access,
LLVMContext::MD_access_group});
if (AATags)
Store->setAAMetadata(AATags.shift(NewBeginOffset - BeginOffset));
Store->setAAMetadata(AATags.adjustForAccess(NewBeginOffset - BeginOffset,
V->getType(), DL));

migrateDebugInfo(&OldAI, IsSplit, NewBeginOffset * 8, SliceSize * 8, &SI,
Store, Store->getPointerOperand(),
Expand Down Expand Up @@ -3098,7 +3104,8 @@ class AllocaSliceRewriter : public InstVisitor<AllocaSliceRewriter, bool> {
NewSI->copyMetadata(SI, {LLVMContext::MD_mem_parallel_loop_access,
LLVMContext::MD_access_group});
if (AATags)
NewSI->setAAMetadata(AATags.shift(NewBeginOffset - BeginOffset));
NewSI->setAAMetadata(AATags.adjustForAccess(NewBeginOffset - BeginOffset,
V->getType(), DL));
if (SI.isVolatile())
NewSI->setAtomic(SI.getOrdering(), SI.getSyncScopeID());
if (NewSI->isAtomic())
Expand Down Expand Up @@ -3200,12 +3207,14 @@ class AllocaSliceRewriter : public InstVisitor<AllocaSliceRewriter, bool> {
// a single value type, just emit a memset.
if (!CanContinue) {
Type *SizeTy = II.getLength()->getType();
Constant *Size = ConstantInt::get(SizeTy, NewEndOffset - NewBeginOffset);
unsigned Sz = NewEndOffset - NewBeginOffset;
Constant *Size = ConstantInt::get(SizeTy, Sz);
MemIntrinsic *New = cast<MemIntrinsic>(IRB.CreateMemSet(
getNewAllocaSlicePtr(IRB, OldPtr->getType()), II.getValue(), Size,
MaybeAlign(getSliceAlign()), II.isVolatile()));
if (AATags)
New->setAAMetadata(AATags.shift(NewBeginOffset - BeginOffset));
New->setAAMetadata(
AATags.adjustForAccess(NewBeginOffset - BeginOffset, Sz));

migrateDebugInfo(&OldAI, IsSplit, NewBeginOffset * 8, SliceSize * 8, &II,
New, New->getRawDest(), nullptr, DL);
Expand Down Expand Up @@ -3281,7 +3290,8 @@ class AllocaSliceRewriter : public InstVisitor<AllocaSliceRewriter, bool> {
New->copyMetadata(II, {LLVMContext::MD_mem_parallel_loop_access,
LLVMContext::MD_access_group});
if (AATags)
New->setAAMetadata(AATags.shift(NewBeginOffset - BeginOffset));
New->setAAMetadata(AATags.adjustForAccess(NewBeginOffset - BeginOffset,
V->getType(), DL));

migrateDebugInfo(&OldAI, IsSplit, NewBeginOffset * 8, SliceSize * 8, &II,
New, New->getPointerOperand(), V, DL);
Expand Down Expand Up @@ -3486,7 +3496,8 @@ class AllocaSliceRewriter : public InstVisitor<AllocaSliceRewriter, bool> {
Load->copyMetadata(II, {LLVMContext::MD_mem_parallel_loop_access,
LLVMContext::MD_access_group});
if (AATags)
Load->setAAMetadata(AATags.shift(NewBeginOffset - BeginOffset));
Load->setAAMetadata(AATags.adjustForAccess(NewBeginOffset - BeginOffset,
Load->getType(), DL));
Src = Load;
}

Expand All @@ -3508,7 +3519,8 @@ class AllocaSliceRewriter : public InstVisitor<AllocaSliceRewriter, bool> {
Store->copyMetadata(II, {LLVMContext::MD_mem_parallel_loop_access,
LLVMContext::MD_access_group});
if (AATags)
Store->setAAMetadata(AATags.shift(NewBeginOffset - BeginOffset));
Store->setAAMetadata(AATags.adjustForAccess(NewBeginOffset - BeginOffset,
Src->getType(), DL));

APInt Offset(DL.getIndexTypeSizeInBits(DstPtr->getType()), 0);
if (IsDest) {
Expand Down Expand Up @@ -3836,7 +3848,8 @@ class AggLoadStoreRewriter : public InstVisitor<AggLoadStoreRewriter, bool> {
DL.getIndexSizeInBits(Ptr->getType()->getPointerAddressSpace()), 0);
if (AATags &&
GEPOperator::accumulateConstantOffset(BaseTy, GEPIndices, DL, Offset))
Load->setAAMetadata(AATags.shift(Offset.getZExtValue()));
Load->setAAMetadata(
AATags.adjustForAccess(Offset.getZExtValue(), Load->getType(), DL));

Agg = IRB.CreateInsertValue(Agg, Load, Indices, Name + ".insert");
LLVM_DEBUG(dbgs() << " to: " << *Load << "\n");
Expand Down Expand Up @@ -3887,8 +3900,10 @@ class AggLoadStoreRewriter : public InstVisitor<AggLoadStoreRewriter, bool> {
APInt Offset(
DL.getIndexSizeInBits(Ptr->getType()->getPointerAddressSpace()), 0);
GEPOperator::accumulateConstantOffset(BaseTy, GEPIndices, DL, Offset);
if (AATags)
Store->setAAMetadata(AATags.shift(Offset.getZExtValue()));
if (AATags) {
Store->setAAMetadata(AATags.adjustForAccess(
Offset.getZExtValue(), ExtractValue->getType(), DL));
}

// migrateDebugInfo requires the base Alloca. Walk to it from this gep.
// If we cannot (because there's an intervening non-const or unbounded
Expand Down Expand Up @@ -4542,6 +4557,7 @@ bool SROA::presplitLoadsAndStores(AllocaInst &AI, AllocaSlices &AS) {

Value *StoreBasePtr = SI->getPointerOperand();
IRB.SetInsertPoint(SI);
AAMDNodes AATags = SI->getAAMetadata();

LLVM_DEBUG(dbgs() << " Splitting store of load: " << *SI << "\n");

Expand All @@ -4561,6 +4577,10 @@ bool SROA::presplitLoadsAndStores(AllocaInst &AI, AllocaSlices &AS) {
PStore->copyMetadata(*SI, {LLVMContext::MD_mem_parallel_loop_access,
LLVMContext::MD_access_group,
LLVMContext::MD_DIAssignID});

if (AATags)
PStore->setAAMetadata(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this part covered in a testcase ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be now, I added a number of additional tests that should cover all cases here

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thx !

AATags.adjustForAccess(PartOffset, PLoad->getType(), DL));
LLVM_DEBUG(dbgs() << " +" << PartOffset << ":" << *PStore << "\n");
}

Expand Down
21 changes: 10 additions & 11 deletions llvm/test/Transforms/SROA/tbaa-struct2.ll
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ define double @bar(ptr %wishart) {
; CHECK-NEXT: [[TMP_SROA_3:%.*]] = alloca [4 x i8], align 4
; CHECK-NEXT: [[TMP_SROA_0_0_COPYLOAD:%.*]] = load double, ptr [[WISHART:%.*]], align 8, !tbaa.struct [[TBAA_STRUCT0:![0-9]+]]
; CHECK-NEXT: [[TMP_SROA_2_0_WISHART_SROA_IDX:%.*]] = getelementptr inbounds i8, ptr [[WISHART]], i64 8
; CHECK-NEXT: [[TMP_SROA_2_0_COPYLOAD:%.*]] = load i32, ptr [[TMP_SROA_2_0_WISHART_SROA_IDX]], align 8, !tbaa.struct [[TBAA_STRUCT7:![0-9]+]]
; CHECK-NEXT: [[TMP_SROA_2_0_COPYLOAD:%.*]] = load i32, ptr [[TMP_SROA_2_0_WISHART_SROA_IDX]], align 8, !tbaa [[TBAA5:![0-9]+]]
; CHECK-NEXT: [[TMP_SROA_3_0_WISHART_SROA_IDX:%.*]] = getelementptr inbounds i8, ptr [[WISHART]], i64 12
; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[TMP_SROA_3]], ptr align 4 [[TMP_SROA_3_0_WISHART_SROA_IDX]], i64 4, i1 false), !tbaa.struct [[TBAA_STRUCT8:![0-9]+]]
; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[TMP_SROA_3]], ptr align 4 [[TMP_SROA_3_0_WISHART_SROA_IDX]], i64 4, i1 false), !tbaa.struct [[TBAA_STRUCT7:![0-9]+]]
; CHECK-NEXT: [[CALL:%.*]] = call double @subcall(double [[TMP_SROA_0_0_COPYLOAD]], i32 [[TMP_SROA_2_0_COPYLOAD]])
; CHECK-NEXT: ret double [[CALL]]
;
Expand All @@ -38,15 +38,14 @@ define double @bar(ptr %wishart) {
;.
; CHECK: attributes #[[ATTR0:[0-9]+]] = { nocallback nofree nounwind willreturn memory(argmem: readwrite) }
;.
; CHECK: [[TBAA_STRUCT0]] = !{i64 0, i64 8, !1, i64 8, i64 4, !5}
; CHECK: [[META1:![0-9]+]] = !{!2, !2, i64 0}
; CHECK: [[META2:![0-9]+]] = !{!"double", !3, i64 0}
; CHECK: [[META3:![0-9]+]] = !{!"omnipotent char", !4, i64 0}
; CHECK: [[META4:![0-9]+]] = !{!"Simple C++ TBAA"}
; CHECK: [[META5:![0-9]+]] = !{!6, !6, i64 0}
; CHECK: [[META6:![0-9]+]] = !{!"int", !3, i64 0}
; CHECK: [[TBAA_STRUCT7]] = !{i64 0, i64 4, !5}
; CHECK: [[TBAA_STRUCT8]] = !{}
; CHECK: [[TBAA_STRUCT0]] = !{i64 0, i64 8, [[META1:![0-9]+]], i64 8, i64 4, [[TBAA5]]}
; CHECK: [[META1]] = !{[[META2:![0-9]+]], [[META2]], i64 0}
; CHECK: [[META2]] = !{!"double", [[META3:![0-9]+]], i64 0}
; CHECK: [[META3]] = !{!"omnipotent char", [[META4:![0-9]+]], i64 0}
; CHECK: [[META4]] = !{!"Simple C++ TBAA"}
; CHECK: [[TBAA5]] = !{[[META6:![0-9]+]], [[META6]], i64 0}
; CHECK: [[META6]] = !{!"int", [[META3]], i64 0}
; CHECK: [[TBAA_STRUCT7]] = !{}
;.
;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
; CHECK-MODIFY-CFG: {{.*}}
Expand Down
Loading