Skip to content

Commit d48a30b

Browse files
committed
[DebugInfo] Emit debug info for witness tables
This change emits debug info for witness tables passed into generic functions when a generic type is constrained to a protocol. This information is required for LLDB's generic expression evaluator to work in such functions. rdar://104446865
1 parent 653925b commit d48a30b

15 files changed

+195
-101
lines changed

include/swift/AST/Types.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7204,7 +7204,10 @@ class GenericTypeParamType : public SubstitutableType,
72047204

72057205
/// Get the name of the generic type parameter.
72067206
Identifier getName() const;
7207-
7207+
7208+
/// Get the canonical <tau>_n_n name;
7209+
Identifier getCanonicalName() const;
7210+
72087211
/// The depth of this generic type parameter, i.e., the number of outer
72097212
/// levels of generic parameter lists that enclose this type parameter.
72107213
///

lib/AST/Type.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2085,8 +2085,10 @@ Identifier GenericTypeParamType::getName() const {
20852085
if (!isCanonical())
20862086
return Name;
20872087

2088-
// Otherwise, we're canonical. Produce an anonymous '<tau>_n_n' name.
2088+
return getCanonicalName();
2089+
}
20892090

2091+
Identifier GenericTypeParamType::getCanonicalName() const {
20902092
// getASTContext() doesn't actually mutate an already-canonical type.
20912093
auto &C = const_cast<GenericTypeParamType*>(this)->getASTContext();
20922094
auto &names = C.CanonicalGenericTypeParamTypeNames;

lib/IRGen/IRGenDebugInfo.cpp

Lines changed: 52 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -279,8 +279,16 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo {
279279
DebugTypeInfo DebugType,
280280
bool IsLocalToUnit,
281281
std::optional<SILLocation> Loc);
282+
283+
void emitArtificialVariable(IRGenFunction &IGF, llvm::Value *Metadata,
284+
StringRef Name, StringRef Identifier);
285+
282286
void emitTypeMetadata(IRGenFunction &IGF, llvm::Value *Metadata,
283-
unsigned Depth, unsigned Index, StringRef Name);
287+
GenericTypeParamType *Type);
288+
289+
void emitWitnessTable(IRGenFunction &IGF, llvm::Value *Metadata,
290+
StringRef Name, ProtocolDecl *protocol);
291+
284292
void emitPackCountParameter(IRGenFunction &IGF, llvm::Value *Metadata,
285293
SILDebugVariable VarInfo);
286294

@@ -3801,9 +3809,10 @@ void IRGenDebugInfoImpl::emitGlobalVariableDeclaration(
38013809
Var->addDebugInfo(GV);
38023810
}
38033811

3804-
void IRGenDebugInfoImpl::emitTypeMetadata(IRGenFunction &IGF,
3805-
llvm::Value *Metadata, unsigned Depth,
3806-
unsigned Index, StringRef Name) {
3812+
void IRGenDebugInfoImpl::emitArtificialVariable(IRGenFunction &IGF,
3813+
llvm::Value *Metadata,
3814+
StringRef Name,
3815+
StringRef Identifier) {
38073816
if (Opts.DebugInfoLevel <= IRGenDebugInfoLevel::LineTables)
38083817
return;
38093818

@@ -3812,23 +3821,42 @@ void IRGenDebugInfoImpl::emitTypeMetadata(IRGenFunction &IGF,
38123821
if (!DS || DS->getInlinedFunction()->isTransparent())
38133822
return;
38143823

3815-
llvm::SmallString<8> Buf;
3816-
static const char *Tau = SWIFT_UTF8("\u03C4");
3817-
llvm::raw_svector_ostream OS(Buf);
3818-
OS << '$' << Tau << '_' << Depth << '_' << Index;
3819-
uint64_t PtrWidthInBits = CI.getTargetInfo().getPointerWidth(clang::LangAS::Default);
3824+
uint64_t PtrWidthInBits =
3825+
CI.getTargetInfo().getPointerWidth(clang::LangAS::Default);
38203826
assert(PtrWidthInBits % 8 == 0);
38213827
auto DbgTy = DebugTypeInfo::getTypeMetadata(
38223828
getMetadataType(Name)->getDeclaredInterfaceType().getPointer(),
38233829
Size(PtrWidthInBits / 8),
38243830
Alignment(CI.getTargetInfo().getPointerAlign(clang::LangAS::Default)));
3825-
emitVariableDeclaration(IGF.Builder, Metadata, DbgTy, IGF.getDebugScope(),
3826-
{}, {OS.str().str(), 0, false},
3827-
// swift.type is already a pointer type,
3828-
// having a shadow copy doesn't add another
3829-
// layer of indirection.
3830-
IGF.isAsync() ? CoroDirectValue : DirectValue,
3831-
ArtificialValue);
3831+
emitVariableDeclaration(
3832+
IGF.Builder, Metadata, DbgTy, IGF.getDebugScope(), {},
3833+
{Identifier, 0, false}, // swift.type is already a pointer type,
3834+
// having a shadow copy doesn't add another
3835+
// layer of indirection.
3836+
IGF.isAsync() ? CoroDirectValue : DirectValue, ArtificialValue);
3837+
}
3838+
3839+
void IRGenDebugInfoImpl::emitTypeMetadata(IRGenFunction &IGF,
3840+
llvm::Value *Metadata,
3841+
GenericTypeParamType *Type) {
3842+
auto Name = Type->getName().str();
3843+
auto CanonicalName = Type->getCanonicalName().str();
3844+
3845+
emitArtificialVariable(IGF, Metadata, Name, CanonicalName);
3846+
}
3847+
3848+
void IRGenDebugInfoImpl::emitWitnessTable(IRGenFunction &IGF,
3849+
llvm::Value *Metadata, StringRef Name,
3850+
ProtocolDecl *protocol) {
3851+
llvm::SmallString<64> Buf;
3852+
llvm::raw_svector_ostream OS(Buf);
3853+
DebugTypeInfo DbgTy(protocol->getInterfaceType());
3854+
auto MangledName = getMangledName(DbgTy);
3855+
OS << "$WT_" << Name << "_" << MangledName;
3856+
// Make sure this ID lives long enough.
3857+
auto Id = IGF.getSwiftModule()->getASTContext().getIdentifier(OS.str());
3858+
3859+
emitArtificialVariable(IGF, Metadata, Name, Id.str());
38323860
}
38333861

38343862
void IRGenDebugInfoImpl::emitPackCountParameter(IRGenFunction &IGF,
@@ -3967,10 +3995,15 @@ void IRGenDebugInfo::emitGlobalVariableDeclaration(
39673995
}
39683996

39693997
void IRGenDebugInfo::emitTypeMetadata(IRGenFunction &IGF, llvm::Value *Metadata,
3970-
unsigned Depth, unsigned Index,
3971-
StringRef Name) {
3998+
GenericTypeParamType *Type) {
39723999
static_cast<IRGenDebugInfoImpl *>(this)->emitTypeMetadata(IGF, Metadata,
3973-
Depth, Index, Name);
4000+
Type);
4001+
}
4002+
4003+
void IRGenDebugInfo::emitWitnessTable(IRGenFunction &IGF, llvm::Value *Metadata,
4004+
StringRef Name, ProtocolDecl *protocol) {
4005+
static_cast<IRGenDebugInfoImpl *>(this)->emitWitnessTable(IGF, Metadata, Name,
4006+
protocol);
39744007
}
39754008

39764009
void IRGenDebugInfo::emitPackCountParameter(IRGenFunction &IGF,

lib/IRGen/IRGenDebugInfo.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,11 @@ class IRGenDebugInfo {
186186

187187
/// Emit debug metadata for type metadata (for generic types). So meta.
188188
void emitTypeMetadata(IRGenFunction &IGF, llvm::Value *Metadata,
189-
unsigned Depth, unsigned Index, StringRef Name);
189+
GenericTypeParamType *Type);
190+
191+
/// Emit debug metadata for a (protocol) witness table.
192+
void emitWitnessTable(IRGenFunction &IGF, llvm::Value *Metadata,
193+
StringRef Name, ProtocolDecl *protocol);
190194

191195
/// Emit debug info for the IR function parameter holding the size of one or
192196
/// more parameter / type packs.

lib/IRGen/LocalTypeData.cpp

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -412,22 +412,38 @@ static void maybeEmitDebugInfoForLocalTypeData(IRGenFunction &IGF,
412412
if (DS && DS->getInlinedFunction() &&
413413
DS->getInlinedFunction()->isTransparent())
414414
return;
415-
416-
// Only for formal type metadata.
417-
if (key.Kind != LocalTypeDataKind::forFormalTypeMetadata())
415+
// For formal type metadata and witness tables.
416+
ProtocolDecl *proto = nullptr;
417+
418+
if (key.Kind.isAbstractProtocolConformance())
419+
proto = key.Kind.getAbstractProtocolConformance();
420+
else if (key.Kind.isConcreteProtocolConformance())
421+
proto = key.Kind.getConcreteProtocolConformance()->getProtocol();
422+
else if (key.Kind != LocalTypeDataKind::forFormalTypeMetadata())
418423
return;
419424

420425
// Only for archetypes, and not for opened/opaque archetypes.
421426
auto type = dyn_cast<ArchetypeType>(key.Type);
422427
if (!type)
423428
return;
424-
if (!type->isRoot())
429+
if (!type->isRoot() && !proto)
425430
return;
426431
if (!isa<PrimaryArchetypeType>(type) && !isa<PackArchetypeType>(type))
427432
return;
428433

429-
auto *typeParam = type->getInterfaceType()->castTo<GenericTypeParamType>();
430-
auto name = typeParam->getName().str();
434+
auto interfaceType = type->getInterfaceType();
435+
llvm::StringRef name;
436+
if (auto DMT =
437+
llvm::dyn_cast<DependentMemberType>(interfaceType.getPointer())) {
438+
name = DMT->getName().str();
439+
} else if (auto GTPT = llvm::dyn_cast<GenericTypeParamType>(
440+
interfaceType.getPointer())) {
441+
name = GTPT->getName().str();
442+
if (name.empty())
443+
name = GTPT->getCanonicalName().str();
444+
} else {
445+
return;
446+
}
431447

432448
llvm::Value *data = value.getMetadata();
433449

@@ -447,10 +463,12 @@ static void maybeEmitDebugInfoForLocalTypeData(IRGenFunction &IGF,
447463
if (!IGF.IGM.DebugInfo)
448464
return;
449465

450-
IGF.IGM.DebugInfo->emitTypeMetadata(IGF, data,
451-
typeParam->getDepth(),
452-
typeParam->getIndex(),
453-
name);
466+
if (proto) {
467+
IGF.IGM.DebugInfo->emitWitnessTable(IGF, data, name, proto);
468+
} else {
469+
auto *typeParam = type->getInterfaceType()->castTo<GenericTypeParamType>();
470+
IGF.IGM.DebugInfo->emitTypeMetadata(IGF, data, typeParam);
471+
}
454472
}
455473

456474
void

test/DebugInfo/move_function_dbginfo.swift

Lines changed: 6 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -237,19 +237,19 @@ public func copyableVarArgTest(_ k: inout Klass) {
237237
// DWARF-NEXT: DW_AT_artificial (true)
238238
//
239239
// DWARF: DW_TAG_variable
240+
// DWARF: DW_AT_location
241+
// DWARF: DW_AT_name ("$WT_T_$s3out1P_pmD")
242+
// DWARF: DW_AT_type (
243+
// DWARF: DW_AT_artificial (true)
244+
//
245+
// DWARF: DW_TAG_variable
240246
// DWARF-NEXT: DW_AT_location (0x{{[a-z0-9]+}}:
241247
// DWARF-NEXT: [0x{{[a-z0-9]+}}, 0x{{[a-z0-9]+}}):
242248
// DWARF-NEXT: DW_AT_name ("k")
243249
// DWARF-NEXT: DW_AT_decl_file (
244250
// DWARF-NEXT: DW_AT_decl_line (
245251
// DWARF-NEXT: DW_AT_type (
246252
//
247-
// DWARF: DW_TAG_variable
248-
// DWARF-NEXT: DW_AT_location (
249-
// DWARF-NEXT: DW_AT_name ("m")
250-
// DWARF-NEXT: DW_AT_decl_file (
251-
// DWARF-NEXT: DW_AT_decl_line (
252-
// DWARF-NEXT: DW_AT_type (
253253
public func addressOnlyValueTest<T : P>(_ x: T) {
254254
let k = x
255255
k.doSomething()
@@ -265,33 +265,6 @@ public func addressOnlyValueTest<T : P>(_ x: T) {
265265
// CHECK: ret void
266266
// CHECK-NEXT: }
267267
//
268-
// DWARF: DW_AT_linkage_name ("$s3out23addressOnlyValueArgTestyyxnAA1PRzlF")
269-
// DWARF-NEXT: DW_AT_name ("addressOnlyValueArgTest")
270-
// DWARF-NEXT: DW_AT_decl_file (
271-
// DWARF-NEXT: DW_AT_decl_line (
272-
// DWARF-NEXT: DW_AT_type (
273-
// DWARF-NEXT: DW_AT_external (
274-
//
275-
// DWARF: DW_TAG_formal_parameter
276-
// DWARF-NEXT: DW_AT_location (0x{{[a-z0-9]+}}:
277-
// DWARF-NEXT: [0x{{[a-z0-9]+}}, 0x{{[a-z0-9]+}}):
278-
// DWARF-NEXT: DW_AT_name ("k")
279-
// DWARF-NEXT: DW_AT_decl_file (
280-
// DWARF-NEXT: DW_AT_decl_line (
281-
// DWARF-NEXT: DW_AT_type (
282-
//
283-
// DWARF: DW_TAG_variable
284-
// DWARF-NEXT: DW_AT_location (
285-
// DWARF-NEXT: DW_AT_name ("$\317\204_0_0")
286-
// DWARF-NEXT: DW_AT_type (
287-
// DWARF-NEXT: DW_AT_artificial (true)
288-
//
289-
// DWARF: DW_TAG_variable
290-
// DWARF-NEXT: DW_AT_location (
291-
// DWARF-NEXT: DW_AT_name ("m")
292-
// DWARF-NEXT: DW_AT_decl_file (
293-
// DWARF-NEXT: DW_AT_decl_line (
294-
// DWARF-NEXT: DW_AT_type (
295268
public func addressOnlyValueArgTest<T : P>(_ k: __owned T) {
296269
k.doSomething()
297270
let m = consume k
@@ -306,35 +279,6 @@ public func addressOnlyValueArgTest<T : P>(_ k: __owned T) {
306279
// CHECK: ret void
307280
// CHECK-NEXT: }
308281
//
309-
// DWARF: DW_AT_linkage_name ("$s3out18addressOnlyVarTestyyxAA1PRzlF")
310-
// DWARF-NEXT: DW_AT_name ("addressOnlyVarTest")
311-
// DWARF-NEXT: DW_AT_decl_file (
312-
// DWARF-NEXT: DW_AT_decl_line (
313-
// DWARF-NEXT: DW_AT_type (
314-
// DWARF-NEXT: DW_AT_external (
315-
//
316-
// DWARF: DW_TAG_formal_parameter
317-
// DWARF-NEXT: DW_AT_location (
318-
// DWARF-NEXT: DW_AT_name ("x")
319-
// DWARF-NEXT: DW_AT_decl_file (
320-
// DWARF-NEXT: DW_AT_decl_line (
321-
// DWARF-NEXT: DW_AT_type (
322-
//
323-
// DWARF: DW_TAG_variable
324-
// DWARF-NEXT: DW_AT_location (
325-
// DWARF-NEXT: DW_AT_name ("$\317\204_0_0")
326-
// DWARF-NEXT: DW_AT_type (
327-
// DWARF-NEXT: DW_AT_artificial (true)
328-
//
329-
// DWARF: DW_TAG_variable
330-
// DWARF-NEXT: DW_AT_location (0x{{[a-z0-9]+}}:
331-
// DWARF-NEXT: [0x{{[a-z0-9]+}}, 0x{{[a-z0-9]+}}):
332-
// TODO: Missing def in dbg info here.
333-
// DWARF-NEXT: [0x{{[a-z0-9]+}}, 0x{{[a-z0-9]+}}):
334-
// DWARF-NEXT: DW_AT_name ("k")
335-
// DWARF-NEXT: DW_AT_decl_file (
336-
// DWARF-NEXT: DW_AT_decl_line (
337-
// DWARF-NEXT: DW_AT_type (
338282
public func addressOnlyVarTest<T : P>(_ x: T) {
339283
var k = x // << this
340284
k.doSomething()

test/DebugInfo/witness_table.swift

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
// RUN: %target-swift-frontend %s -emit-ir -g -o -
2+
import StdlibUnittest
3+
protocol P1 {}
4+
protocol P2 {}
5+
protocol P3 {}
6+
protocol P4 {}
7+
protocol P5 {}
8+
9+
struct I: P1, P2, P4 {}
10+
struct I2: P3 {}
11+
struct I3: P5 {}
12+
13+
struct S<T, U: P3> where T: P1, T: P2 {
14+
let t: T
15+
let u: U
16+
17+
func foo() {
18+
}
19+
//CHECK: ![[foo:[0-9]+]] = distinct !DISubprogram(name: "foo", linkageName: "$s13witness_table1SV3fooyyF",
20+
//CHECK: !DILocalVariable(name: "$WT_T_$s13witness_table2P1_pmD", scope: ![[foo]], {{.*}}, flags: DIFlagArtificial)
21+
//CHECK: !DILocalVariable(name: "$WT_T_$s13witness_table2P2_pmD", scope: ![[foo]], {{.*}}, flags: DIFlagArtificial)
22+
//CHECK: !DILocalVariable(name: "$\CF\84_0_0", scope: ![[foo]], {{.*}}, flags: DIFlagArtificial)
23+
//CHECK: !DILocalVariable(name: "$WT_U_$s13witness_table2P3_pmD", scope: ![[foo]], {{.*}}, flags: DIFlagArtificial)
24+
//CHECK: !DILocalVariable(name: "$\CF\84_0_1", scope: ![[foo]], {{.*}}, flags: DIFlagArtificial)
25+
26+
func bar<V: P4>(v: V) {
27+
}
28+
//CHECK: ![[bar:[0-9]+]] = distinct !DISubprogram(name: "bar", linkageName: "$s13witness_table1SV3bar1vyqd___tAA2P4Rd__lF",
29+
//CHECK: !DILocalVariable(name: "$\CF\84_1_0", scope: ![[bar]], {{.*}}, flags: DIFlagArtificial)
30+
//CHECK: !DILocalVariable(name: "$WT_V_$s13witness_table2P4_pmD", scope: ![[bar]], {{.*}}, flags: DIFlagArtificial)
31+
//CHECK: !DILocalVariable(name: "$WT_T_$s13witness_table2P1_pmD", scope: ![[bar]], {{.*}}, flags: DIFlagArtificial)
32+
//CHECK: !DILocalVariable(name: "$WT_T_$s13witness_table2P2_pmD", scope: ![[bar]], {{.*}}, flags: DIFlagArtificial)
33+
//CHECK: !DILocalVariable(name: "$\CF\84_0_0", scope: ![[bar]], {{.*}}, flags: DIFlagArtificial)
34+
//CHECK: !DILocalVariable(name: "$WT_U_$s13witness_table2P3_pmD", scope: ![[bar]], {{.*}}, flags: DIFlagArtificial)
35+
//CHECK: !DILocalVariable(name: "$\CF\84_0_1", scope: ![[bar]], {{.*}}, flags: DIFlagArtificial)
36+
}
37+
38+
extension S where T: P5 {
39+
func baz() {
40+
}
41+
42+
//CHECK: ![[baz:[0-9]+]] = distinct !DISubprogram(name: "baz", linkageName: "$s13witness_table1SVA2A2P5RzrlE3bazyyF",
43+
//CHECK: !DILocalVariable(name: "$WT_T_$s13witness_table2P5_pmD", scope: ![[baz]], {{.*}}, flags: DIFlagArtificial)
44+
//CHECK: !DILocalVariable(name: "$WT_T_$s13witness_table2P1_pmD", scope: ![[baz]], {{.*}}, flags: DIFlagArtificial)
45+
//CHECK: !DILocalVariable(name: "$WT_T_$s13witness_table2P2_pmD", scope: ![[baz]], {{.*}}, flags: DIFlagArtificial)
46+
//CHECK: !DILocalVariable(name: "$\CF\84_0_0", scope: ![[baz]], {{.*}}, flags: DIFlagArtificial)
47+
//CHECK: !DILocalVariable(name: "$WT_U_$s13witness_table2P3_pmD", scope: ![[baz]], {{.*}}, flags: DIFlagArtificial)
48+
//CHECK: !DILocalVariable(name: "$\CF\84_0_1", scope: ![[baz]], {{.*}}, flags: DIFlagArtificial)
49+
}
50+
51+
S(t: I(), u: I2())
52+
53+
func freeFunc<T1: P1, T2>(t1: T1, t2: T2) where T2: P3, T2: P4 {
54+
}
55+
//CHECK: ![[freeFunc:[0-9]+]] = distinct !DISubprogram(name: "freeFunc", linkageName: "$s13witness_table8freeFunc2t12t2yx_q_tAA2P1RzAA2P3R_AA2P4R_r0_lF",
56+
//CHECK: !DILocalVariable(name: "$\CF\84_0_0", scope: ![[freeFunc]], {{.*}}, flags: DIFlagArtificial)
57+
//CHECK: !DILocalVariable(name: "$\CF\84_0_1", scope: ![[freeFunc]], {{.*}}, flags: DIFlagArtificial)
58+
//CHECK: !DILocalVariable(name: "$WT_T1_$s13witness_table2P1_pmD", scope: ![[freeFunc]], {{.*}}, flags: DIFlagArtificial)
59+
//CHECK: !DILocalVariable(name: "$WT_T2_$s13witness_table2P3_pmD", scope: ![[freeFunc]], {{.*}}, flags: DIFlagArtificial)
60+
//CHECK: !DILocalVariable(name: "$WT_T2_$s13witness_table2P4_pmD", scope: ![[freeFunc]], {{.*}}, flags: DIFlagArtificial)
61+
62+
protocol A {
63+
associatedtype Element
64+
}
65+
66+
func withAssociatedType<T: A>(_: T) where T.Element: A {
67+
}
68+
69+
//CHECK: ![[withAssociatedType:[0-9]+]] = distinct !DISubprogram(name: "withAssociatedType", linkageName: "$s13witness_table18withAssociatedTypeyyxAA1ARzAaC7ElementRpzlF"
70+
//CHECK: !DILocalVariable(name: "$\CF\84_0_0", scope: ![[withAssociatedType]], {{.*}}, flags: DIFlagArtificial)
71+
//CHECK: !DILocalVariable(name: "$WT_T_$s13witness_table1A_pmD", scope: ![[withAssociatedType]], {{.*}}, flags: DIFlagArtificial)
72+
//CHECK: !DILocalVariable(name: "$WT_T.Element_$s13witness_table1A_pmD", scope: ![[withAssociatedType]], {{.*}}, flags: DIFlagArtificial)
73+

test/IRGen/associated_type_witness.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,12 +73,14 @@ struct Fulfilled<T : P & Q> : Assocked {
7373
// CHECK-LABEL: define internal swiftcc ptr @"$s23associated_type_witness9FulfilledVyxGAA8AssockedAA5AssocAaEP_AA1PPWT"(ptr %"Fulfilled<T>.Assoc", ptr %"Fulfilled<T>", ptr %"Fulfilled<T>.Assocked")
7474
// CHECK: [[T1:%.*]] = getelementptr inbounds ptr, ptr %"Fulfilled<T>", i64 3
7575
// CHECK-NEXT: [[T2:%.*]] = load ptr, ptr [[T1]], align 8, !invariant.load
76+
// CHECK-NEXT: store ptr %T.P, ptr %T
7677
// CHECK-NEXT: ret ptr [[T2]]
7778

7879
// Associated type witness table access function for Fulfilled.Assoc : Q.
7980
// CHECK-LABEL: define internal swiftcc ptr @"$s23associated_type_witness9FulfilledVyxGAA8AssockedAA5AssocAaEP_AA1QPWT"(ptr %"Fulfilled<T>.Assoc", ptr %"Fulfilled<T>", ptr %"Fulfilled<T>.Assocked")
8081
// CHECK: [[T1:%.*]] = getelementptr inbounds ptr, ptr %"Fulfilled<T>", i64 4
8182
// CHECK-NEXT: [[T2:%.*]] = load ptr, ptr [[T1]], align 8, !invariant.load
83+
// CHECK-NEXT: store ptr %T.Q, ptr %T
8284
// CHECK-NEXT: ret ptr [[T2]]
8385

8486
struct Pair<T, U> : P, Q {}

0 commit comments

Comments
 (0)