Skip to content

Commit 6248b40

Browse files
committed
fixup! [SROA] Vector promote some memsets
1 parent 39ec377 commit 6248b40

File tree

9 files changed

+293
-252
lines changed

9 files changed

+293
-252
lines changed

clang/test/CodeGenOpenCL/amdgpu-nullptr.cl

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -503,19 +503,21 @@ void cast_bool_generic(generic char* p) {
503503
*p = 0;
504504
}
505505

506-
// Test initialization of a struct with a private member.
506+
// Test initialize a struct using memset.
507+
// For large structures which is mostly zero, clang generats llvm.memset for
508+
// the zero part and store for non-zero members.
507509
typedef struct {
508510
long a, b, c, d;
509511
private char *p;
510512
} StructTy3;
511513

512-
// CHECK-LABEL: test_struct_private_member
513-
// CHECK: store <32 x i8> zeroinitializer, ptr addrspace(5) {{.*}}, align 8
514+
// CHECK-LABEL: test_memset_private
515+
// CHECK: call void @llvm.memset.p5.i64(ptr addrspace(5) noundef align 8 {{.*}}, i8 0, i64 32, i1 false)
514516
// CHECK: [[GEP:%.*]] = getelementptr inbounds nuw i8, ptr addrspace(5) %ptr, i32 32
515517
// CHECK: store ptr addrspace(5) addrspacecast (ptr null to ptr addrspace(5)), ptr addrspace(5) [[GEP]]
516518
// CHECK: [[GEP1:%.*]] = getelementptr inbounds nuw i8, ptr addrspace(5) {{.*}}, i32 36
517519
// CHECK: store i32 0, ptr addrspace(5) [[GEP1]], align 4
518-
void test_struct_private_member(private StructTy3 *ptr) {
520+
void test_memset_private(private StructTy3 *ptr) {
519521
StructTy3 S3 = {0, 0, 0, 0, 0};
520522
*ptr = S3;
521523
}

llvm/lib/Transforms/Scalar/SROA.cpp

Lines changed: 79 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -490,6 +490,10 @@ static void migrateDebugInfo(AllocaInst *OldAlloca, bool IsSplit,
490490
for_each(DVRAssignMarkerRange, MigrateDbgAssign);
491491
}
492492

493+
static Type *getTypePartition(const DataLayout &DL, Type *Ty, uint64_t Offset,
494+
uint64_t Size);
495+
static Type *getTypePartition(const AllocaInst &AI, const Partition &P);
496+
493497
namespace {
494498

495499
/// A custom IRBuilder inserter which prefixes all names, but only in
@@ -1011,37 +1015,33 @@ static Value *foldPHINodeOrSelectInst(Instruction &I) {
10111015
return foldSelectInst(cast<SelectInst>(I));
10121016
}
10131017

1014-
static constexpr size_t getMaxNumFixedVectorElements() {
1015-
// FIXME: hack. Do we have a named constant for this?
1016-
// SDAG SDNode can't have more than 65535 operands.
1017-
return std::numeric_limits<unsigned short>::max();
1018-
}
1019-
10201018
/// Returns a fixed vector type equivalent to the memory set by II or nullptr if
1021-
/// unable to do so.
1022-
static FixedVectorType *getVectorTypeFor(const MemSetInst &II,
1023-
const DataLayout &DL) {
1019+
/// not viable.
1020+
static FixedVectorType *getVectorTypeFor(const DataLayout &DL, Type *PartTy,
1021+
const MemSetInst &II) {
1022+
auto *PartVecTy = dyn_cast_or_null<FixedVectorType>(PartTy);
1023+
if (!PartVecTy)
1024+
return nullptr;
1025+
1026+
const uint64_t PartVecSize = DL.getTypeStoreSize(PartVecTy).getFixedValue();
1027+
10241028
const ConstantInt *Length = dyn_cast<ConstantInt>(II.getLength());
10251029
if (!Length)
10261030
return nullptr;
10271031

10281032
const APInt &Val = Length->getValue();
1029-
if (Val.ugt(getMaxNumFixedVectorElements()))
1033+
if (Val.ugt(PartVecSize))
10301034
return nullptr;
10311035

10321036
// Element type will always be i8. TODO: Support
10331037
// llvm.experimental.memset.pattern?
1034-
uint64_t MemSetLen = Val.getZExtValue();
1035-
auto *VTy = FixedVectorType::get(II.getValue()->getType(), MemSetLen);
1036-
1037-
// FIXME: This is a workaround. Vector promotion sometimes inhibits our
1038-
// ability to merge constant stores. It seems to be related to the presence of
1039-
// alignment bytes. See
1040-
// test/Transforms/PhaseOrdering/X86/store-constant-merge.ll
1041-
if (MemSetLen != DL.getTypeAllocSize(VTy).getFixedValue())
1042-
return nullptr;
1038+
return FixedVectorType::get(II.getValue()->getType(), Val.getZExtValue());
1039+
}
10431040

1044-
return VTy;
1041+
static FixedVectorType *getVectorTypeFor(const AllocaInst &AI,
1042+
const Partition &P,
1043+
const MemSetInst &II) {
1044+
return getVectorTypeFor(AI.getDataLayout(), getTypePartition(AI, P), II);
10451045
}
10461046

10471047
/// Builder for the alloca slices.
@@ -1055,6 +1055,7 @@ class AllocaSlices::SliceBuilder : public PtrUseVisitor<SliceBuilder> {
10551055
using Base = PtrUseVisitor<SliceBuilder>;
10561056

10571057
const uint64_t AllocSize;
1058+
const AllocaInst &AI;
10581059
AllocaSlices &AS;
10591060

10601061
SmallDenseMap<Instruction *, unsigned> MemTransferSliceMap;
@@ -1067,7 +1068,7 @@ class AllocaSlices::SliceBuilder : public PtrUseVisitor<SliceBuilder> {
10671068
SliceBuilder(const DataLayout &DL, AllocaInst &AI, AllocaSlices &AS)
10681069
: PtrUseVisitor<SliceBuilder>(DL),
10691070
AllocSize(DL.getTypeAllocSize(AI.getAllocatedType()).getFixedValue()),
1070-
AS(AS) {}
1071+
AI(AI), AS(AS) {}
10711072

10721073
private:
10731074
void markAsDead(Instruction &I) {
@@ -1132,16 +1133,15 @@ class AllocaSlices::SliceBuilder : public PtrUseVisitor<SliceBuilder> {
11321133
return Base::visitGetElementPtrInst(GEPI);
11331134
}
11341135

1135-
bool isSplittableMemOp(Type *Ty, bool IsVolatile) {
1136-
return Ty->isIntegerTy() && !IsVolatile && DL.typeSizeEqualsStoreSize(Ty);
1137-
}
1138-
11391136
void handleLoadOrStore(Type *Ty, Instruction &I, const APInt &Offset,
11401137
uint64_t Size, bool IsVolatile) {
11411138
// We allow splitting of non-volatile loads and stores where the type is an
11421139
// integer type. These may be used to implement 'memcpy' or other "transfer
11431140
// of bits" patterns.
1144-
insertUse(I, Offset, Size, isSplittableMemOp(Ty, IsVolatile));
1141+
bool IsSplittable =
1142+
Ty->isIntegerTy() && !IsVolatile && DL.typeSizeEqualsStoreSize(Ty);
1143+
1144+
insertUse(I, Offset, Size, IsSplittable);
11451145
}
11461146

11471147
void visitLoadInst(LoadInst &LI) {
@@ -1206,17 +1206,17 @@ class AllocaSlices::SliceBuilder : public PtrUseVisitor<SliceBuilder> {
12061206
if (!IsOffsetKnown)
12071207
return PI.setAborted(&II);
12081208

1209-
bool Splittable;
1210-
1211-
if (getVectorTypeFor(II, DL))
1212-
Splittable = isSplittableMemOp(AS.AI.getAllocatedType(), II.isVolatile());
1213-
else
1214-
Splittable = (bool)Length;
1215-
1216-
insertUse(II, Offset,
1217-
Length ? Length->getLimitedValue()
1218-
: AllocSize - Offset.getLimitedValue(),
1219-
Splittable);
1209+
uint64_t Size = Length ? Length->getLimitedValue()
1210+
: AllocSize - Offset.getLimitedValue();
1211+
bool Splittable = (bool)Length;
1212+
if (Splittable) {
1213+
// Encourage the use of vector types by making this non-splittable if the
1214+
// memset corresponds to viable vector type.
1215+
Type *PartTy = getTypePartition(DL, AI.getAllocatedType(),
1216+
Offset.getLimitedValue(), Size);
1217+
Splittable = !getVectorTypeFor(DL, PartTy, II);
1218+
}
1219+
insertUse(II, Offset, Size, Splittable);
12201220
}
12211221

12221222
void visitMemTransferInst(MemTransferInst &II) {
@@ -2084,10 +2084,11 @@ static Value *convertValue(const DataLayout &DL, IRBuilderTy &IRB, Value *V,
20842084
///
20852085
/// This function is called to test each entry in a partition which is slated
20862086
/// for a single slice.
2087-
static bool isVectorPromotionViableForSlice(Partition &P, const Slice &S,
2088-
VectorType *Ty,
2089-
uint64_t ElementSize,
2090-
const DataLayout &DL) {
2087+
static bool isVectorPromotionViableForSlice(const AllocaInst &AI, Partition &P,
2088+
const Slice &S, VectorType *Ty,
2089+
uint64_t ElementSize) {
2090+
const DataLayout &DL = AI.getDataLayout();
2091+
20912092
// First validate the slice offsets.
20922093
uint64_t BeginOffset =
20932094
std::max(S.beginOffset(), P.beginOffset()) - P.beginOffset();
@@ -2116,14 +2117,14 @@ static bool isVectorPromotionViableForSlice(Partition &P, const Slice &S,
21162117
if (MI->isVolatile())
21172118
return false;
21182119

2119-
auto *II = dyn_cast<MemSetInst>(U->getUser());
2120-
if (!II && !S.isSplittable()) {
2120+
if (!S.isSplittable()) {
21212121
// Skip any non-memset unsplittable intrinsics.
2122-
return false;
2123-
}
2124-
if (II) {
2125-
// For memset, allow if we have a suitable vector type
2126-
Type *VTy = getVectorTypeFor(*II, DL);
2122+
auto *II = dyn_cast<MemSetInst>(U->getUser());
2123+
if (!II)
2124+
return false;
2125+
2126+
// For memset, allow if we have a viable vector type
2127+
Type *VTy = getVectorTypeFor(AI, P, *II);
21272128
if (!VTy)
21282129
return false;
21292130
if (!canConvertValue(DL, SliceTy, VTy))
@@ -2170,8 +2171,9 @@ static bool isVectorPromotionViableForSlice(Partition &P, const Slice &S,
21702171
/// This implements the necessary checking for \c checkVectorTypesForPromotion
21712172
/// (and thus isVectorPromotionViable) over all slices of the alloca for the
21722173
/// given VectorType.
2173-
static bool checkVectorTypeForPromotion(Partition &P, VectorType *VTy,
2174-
const DataLayout &DL) {
2174+
static bool checkVectorTypeForPromotion(const AllocaInst &AI, Partition &P,
2175+
VectorType *VTy) {
2176+
const DataLayout &DL = AI.getDataLayout();
21752177
uint64_t ElementSize =
21762178
DL.getTypeSizeInBits(VTy->getElementType()).getFixedValue();
21772179

@@ -2184,11 +2186,11 @@ static bool checkVectorTypeForPromotion(Partition &P, VectorType *VTy,
21842186
ElementSize /= 8;
21852187

21862188
for (const Slice &S : P)
2187-
if (!isVectorPromotionViableForSlice(P, S, VTy, ElementSize, DL))
2189+
if (!isVectorPromotionViableForSlice(AI, P, S, VTy, ElementSize))
21882190
return false;
21892191

21902192
for (const Slice *S : P.splitSliceTails())
2191-
if (!isVectorPromotionViableForSlice(P, *S, VTy, ElementSize, DL))
2193+
if (!isVectorPromotionViableForSlice(AI, P, *S, VTy, ElementSize))
21922194
return false;
21932195

21942196
return true;
@@ -2199,11 +2201,12 @@ static bool checkVectorTypeForPromotion(Partition &P, VectorType *VTy,
21992201
/// This implements the necessary checking for \c isVectorPromotionViable over
22002202
/// all slices of the alloca for the given VectorType.
22012203
static VectorType *
2202-
checkVectorTypesForPromotion(Partition &P, const DataLayout &DL,
2204+
checkVectorTypesForPromotion(const AllocaInst &AI, Partition &P,
22032205
SmallVectorImpl<VectorType *> &CandidateTys,
22042206
bool HaveCommonEltTy, Type *CommonEltTy,
22052207
bool HaveVecPtrTy, bool HaveCommonVecPtrTy,
22062208
VectorType *CommonVecPtrTy) {
2209+
const DataLayout &DL = AI.getDataLayout();
22072210
// If we didn't find a vector type, nothing to do here.
22082211
if (CandidateTys.empty())
22092212
return nullptr;
@@ -2271,24 +2274,27 @@ checkVectorTypesForPromotion(Partition &P, const DataLayout &DL,
22712274
CandidateTys.resize(1);
22722275
}
22732276

2277+
// FIXME: hack. Do we have a named constant for this?
2278+
// SDAG SDNode can't have more than 65535 operands.
22742279
llvm::erase_if(CandidateTys, [](VectorType *VTy) {
22752280
return cast<FixedVectorType>(VTy)->getNumElements() >
2276-
getMaxNumFixedVectorElements();
2281+
std::numeric_limits<unsigned short>::max();
22772282
});
22782283

22792284
for (VectorType *VTy : CandidateTys)
2280-
if (checkVectorTypeForPromotion(P, VTy, DL))
2285+
if (checkVectorTypeForPromotion(AI, P, VTy))
22812286
return VTy;
22822287

22832288
return nullptr;
22842289
}
22852290

22862291
static VectorType *createAndCheckVectorTypesForPromotion(
22872292
SetVector<Type *> &OtherTys, ArrayRef<VectorType *> CandidateTysCopy,
2288-
function_ref<void(Type *)> CheckCandidateType, Partition &P,
2289-
const DataLayout &DL, SmallVectorImpl<VectorType *> &CandidateTys,
2293+
function_ref<void(Type *)> CheckCandidateType, const AllocaInst &AI,
2294+
Partition &P, SmallVectorImpl<VectorType *> &CandidateTys,
22902295
bool &HaveCommonEltTy, Type *&CommonEltTy, bool &HaveVecPtrTy,
22912296
bool &HaveCommonVecPtrTy, VectorType *&CommonVecPtrTy) {
2297+
const DataLayout &DL = AI.getDataLayout();
22922298
[[maybe_unused]] VectorType *OriginalElt =
22932299
CandidateTysCopy.size() ? CandidateTysCopy[0] : nullptr;
22942300
// Consider additional vector types where the element type size is a
@@ -2313,7 +2319,7 @@ static VectorType *createAndCheckVectorTypesForPromotion(
23132319
}
23142320
}
23152321

2316-
return checkVectorTypesForPromotion(P, DL, CandidateTys, HaveCommonEltTy,
2322+
return checkVectorTypesForPromotion(AI, P, CandidateTys, HaveCommonEltTy,
23172323
CommonEltTy, HaveVecPtrTy,
23182324
HaveCommonVecPtrTy, CommonVecPtrTy);
23192325
}
@@ -2327,9 +2333,10 @@ static VectorType *createAndCheckVectorTypesForPromotion(
23272333
/// SSA value. We only can ensure this for a limited set of operations, and we
23282334
/// don't want to do the rewrites unless we are confident that the result will
23292335
/// be promotable, so we have an early test here.
2330-
static VectorType *isVectorPromotionViable(Partition &P, const DataLayout &DL) {
2336+
static VectorType *isVectorPromotionViable(const AllocaInst &AI, Partition &P) {
23312337
// Collect the candidate types for vector-based promotion. Also track whether
23322338
// we have different element types.
2339+
const DataLayout &DL = AI.getDataLayout();
23332340
SmallVector<VectorType *, 4> CandidateTys;
23342341
SetVector<Type *> LoadStoreTys;
23352342
SetVector<Type *> DeferredTys;
@@ -2375,7 +2382,7 @@ static VectorType *isVectorPromotionViable(Partition &P, const DataLayout &DL) {
23752382
else if (auto *SI = dyn_cast<StoreInst>(S.getUse()->getUser()))
23762383
Ty = SI->getValueOperand()->getType();
23772384
else if (auto *II = dyn_cast<MemSetInst>(S.getUse()->getUser())) {
2378-
Ty = getVectorTypeFor(*II, DL);
2385+
Ty = getVectorTypeFor(AI, P, *II);
23792386
if (!Ty)
23802387
continue;
23812388
} else
@@ -2396,14 +2403,14 @@ static VectorType *isVectorPromotionViable(Partition &P, const DataLayout &DL) {
23962403

23972404
SmallVector<VectorType *, 4> CandidateTysCopy = CandidateTys;
23982405
if (auto *VTy = createAndCheckVectorTypesForPromotion(
2399-
LoadStoreTys, CandidateTysCopy, CheckCandidateType, P, DL,
2406+
LoadStoreTys, CandidateTysCopy, CheckCandidateType, AI, P,
24002407
CandidateTys, HaveCommonEltTy, CommonEltTy, HaveVecPtrTy,
24012408
HaveCommonVecPtrTy, CommonVecPtrTy))
24022409
return VTy;
24032410

24042411
CandidateTys.clear();
24052412
return createAndCheckVectorTypesForPromotion(
2406-
DeferredTys, CandidateTysCopy, CheckCandidateType, P, DL, CandidateTys,
2413+
DeferredTys, CandidateTysCopy, CheckCandidateType, AI, P, CandidateTys,
24072414
HaveCommonEltTy, CommonEltTy, HaveVecPtrTy, HaveCommonVecPtrTy,
24082415
CommonVecPtrTy);
24092416
}
@@ -4386,6 +4393,13 @@ static Type *getTypePartition(const DataLayout &DL, Type *Ty, uint64_t Offset,
43864393
return SubTy;
43874394
}
43884395

4396+
static Type *getTypePartition(const AllocaInst &AI, const Partition &P) {
4397+
if (P.empty())
4398+
return nullptr;
4399+
return getTypePartition(AI.getDataLayout(), AI.getAllocatedType(),
4400+
P.beginOffset(), P.size());
4401+
}
4402+
43894403
/// Pre-split loads and stores to simplify rewriting.
43904404
///
43914405
/// We want to break up the splittable load+store pairs as much as
@@ -4929,12 +4943,12 @@ AllocaInst *SROA::rewritePartition(AllocaInst &AI, AllocaSlices &AS,
49294943

49304944
// If the common use types are not viable for promotion then attempt to find
49314945
// another type that is viable.
4932-
if (SliceVecTy && !checkVectorTypeForPromotion(P, SliceVecTy, DL))
4946+
if (SliceVecTy && !checkVectorTypeForPromotion(AI, P, SliceVecTy))
49334947
if (Type *TypePartitionTy = getTypePartition(DL, AI.getAllocatedType(),
49344948
P.beginOffset(), P.size())) {
49354949
VectorType *TypePartitionVecTy = dyn_cast<VectorType>(TypePartitionTy);
49364950
if (TypePartitionVecTy &&
4937-
checkVectorTypeForPromotion(P, TypePartitionVecTy, DL))
4951+
checkVectorTypeForPromotion(AI, P, TypePartitionVecTy))
49384952
SliceTy = TypePartitionTy;
49394953
}
49404954

@@ -4945,7 +4959,7 @@ AllocaInst *SROA::rewritePartition(AllocaInst &AI, AllocaSlices &AS,
49454959
bool IsIntegerPromotable = isIntegerWideningViable(P, SliceTy, DL);
49464960

49474961
VectorType *VecTy =
4948-
IsIntegerPromotable ? nullptr : isVectorPromotionViable(P, DL);
4962+
IsIntegerPromotable ? nullptr : isVectorPromotionViable(AI, P);
49494963
if (VecTy)
49504964
SliceTy = VecTy;
49514965

llvm/test/DebugInfo/Generic/assignment-tracking/sroa/user-memcpy.ll

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@
2121
;; Allocas have been promoted - the linked dbg.assigns have been removed.
2222

2323
;; | V3i point = {0, 0, 0};
24-
; CHECK-NEXT: #dbg_value(<16 x i8> zeroinitializer, ![[point:[0-9]+]], !DIExpression(DW_OP_LLVM_fragment, 0, 128),
24+
; CHECK-NEXT: #dbg_value(i64 0, ![[point:[0-9]+]], !DIExpression(DW_OP_LLVM_fragment, 0, 64),
25+
; CHECK-NEXT: #dbg_value(i64 0, ![[point]], !DIExpression(DW_OP_LLVM_fragment, 64, 64),
2526

2627
;; point.z = 5000;
2728
; CHECK-NEXT: #dbg_value(i64 5000, ![[point]], !DIExpression(DW_OP_LLVM_fragment, 128, 64),
@@ -31,20 +32,17 @@
3132
;; local.other.x = global.other.x
3233
;; local.other.y = global.other.y
3334
;; local.other.z = global.other.z
34-
; CHECK-NEXT: %other.sroa.0.0.copyload = load <8 x i8>, ptr @__const._Z3funv.other
35+
; CHECK-NEXT: %other.sroa.0.0.copyload = load i64, ptr @__const._Z3funv.other
3536
; CHECK-NEXT: %other.sroa.2.0.copyload = load i64, ptr getelementptr inbounds (i8, ptr @__const._Z3funv.other, i64 8)
3637
; CHECK-NEXT: %other.sroa.3.0.copyload = load i64, ptr getelementptr inbounds (i8, ptr @__const._Z3funv.other, i64 16)
37-
; CHECK-NEXT: #dbg_value(<8 x i8> %other.sroa.0.0.copyload, ![[other:[0-9]+]], !DIExpression(DW_OP_LLVM_fragment, 0, 64),
38+
; CHECK-NEXT: #dbg_value(i64 %other.sroa.0.0.copyload, ![[other:[0-9]+]], !DIExpression(DW_OP_LLVM_fragment, 0, 64),
3839
; CHECK-NEXT: #dbg_value(i64 %other.sroa.2.0.copyload, ![[other]], !DIExpression(DW_OP_LLVM_fragment, 64, 64),
3940
; CHECK-NEXT: #dbg_value(i64 %other.sroa.3.0.copyload, ![[other]], !DIExpression(DW_OP_LLVM_fragment, 128, 64),
4041

4142
;; | std::memcpy(&point.y, &other.x, sizeof(long) * 2);
4243
;; other is now 3 scalars:
4344
;; point.y = other.x
44-
; CHECK-NEXT: %point.sroa.0.sroa.0.8.vec.expand = shufflevector <8 x i8> %other.sroa.0.0.copyload, <8 x i8> poison, <16 x i32> <i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>,
45-
; CHECK-NEXT: %point.sroa.0.sroa.0.8.vecblend = select <16 x i1> <i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 false, i1 true, i1 true, i1 true, i1 true, i1 true, i1 true, i1 true, i1 true>, <16 x i8> %point.sroa.0.sroa.0.8.vec.expand, <16 x i8> zeroinitializer,
46-
; CHECK-NEXT: #dbg_value(<16 x i8> %point.sroa.0.sroa.0.8.vecblend, ![[point]], !DIExpression(DW_OP_LLVM_fragment, 64, 64),
47-
45+
; CHECK-NEXT: #dbg_value(i64 %other.sroa.0.0.copyload, ![[point]], !DIExpression(DW_OP_LLVM_fragment, 64, 64),
4846
;;
4947
;; point.z = other.y
5048
; CHECK-NEXT: #dbg_value(i64 %other.sroa.2.0.copyload, ![[point]], !DIExpression(DW_OP_LLVM_fragment, 128, 64),

llvm/test/DebugInfo/X86/sroasplit-5.ll

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,10 @@ target triple = "x86_64-unknown-linux-gnu"
2121
;
2222
; There should be no debug info for the padding.
2323
; CHECK-NOT: DW_OP_LLVM_fragment, 56
24-
; CHECK: ![[a:[0-9]+]], !DIExpression(),
24+
; CHECK: DIExpression(DW_OP_LLVM_fragment, 0, 32)
25+
; CHECK-NOT: DW_OP_LLVM_fragment, 56
26+
; CHECK: DIExpression(DW_OP_LLVM_fragment, 32, 24)
2527
; CHECK-NOT: DW_OP_LLVM_fragment, 56
26-
; CHECK: ![[a]] = !DILocalVariable(name: "a",
2728
%struct.prog_src_register = type { i32, i24 }
2829

2930
; Function Attrs: nounwind

0 commit comments

Comments
 (0)