Skip to content

Commit b0e424f

Browse files
technicatedToma91
authored andcommitted
Added support for tuples with dynamic layout (ie generic tuples)
Extracted a base CRTP class MetadataVisitor from NominalMetadataVisitor Added new tuple metadata visitors extending the new MetadataVisitor
1 parent 3615b0e commit b0e424f

File tree

6 files changed

+197
-26
lines changed

6 files changed

+197
-26
lines changed

lib/IRGen/GenKeyPath.cpp

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1108,19 +1108,35 @@ emitKeyPathComponent(IRGenModule &IGM,
11081108
break;
11091109
case KeyPathPatternComponent::Kind::TupleElement:
11101110
assert(baseTy->is<TupleType>() && "not a tuple");
1111-
1111+
11121112
SILType loweredTy = IGM.getSILTypes().getLoweredType(baseTy);
11131113

1114+
// Tuple with fixed layout
1115+
//
1116+
// This code is ALSO executed in the case of a tuple with dynamic layout,
1117+
// (see below) but only if `component.getTupleIndex()` is 0 - in that case
1118+
// the compiler knows that the tuple element is always at offset 0
11141119
if (auto offset = getFixedTupleElementOffset(IGM, loweredTy, component.getTupleIndex())) {
11151120
auto header = KeyPathComponentHeader
11161121
::forStructComponentWithInlineOffset(/*isLet*/ false,
11171122
offset->getValue());
1118-
1123+
11191124
fields.addInt32(header.getData());
11201125
break;
11211126
}
1122-
1123-
llvm_unreachable("could not get element offset");
1127+
1128+
// Tuple with dynamic layout
1129+
auto elementOffset = getStaticTupleElementOffset(IGM,
1130+
loweredTy,
1131+
component.getTupleIndex());
1132+
1133+
auto header = KeyPathComponentHeader
1134+
::forStructComponentWithUnresolvedFieldOffset(/*isLet*/ false);
1135+
fields.addInt32(header.getData());
1136+
fields.addInt32(elementOffset.getValue());
1137+
break;
1138+
1139+
llvm_unreachable("could not get tuple element offset");
11241140
}
11251141
}
11261142

lib/IRGen/MetadataLayout.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include "IRGenFunction.h"
3232
#include "StructMetadataVisitor.h"
3333
#include "ForeignClassMetadataVisitor.h"
34+
#include "TupleMetadataVisitor.h"
3435

3536
#include "swift/Basic/LLVM.h"
3637
#include "llvm/ADT/Optional.h"
@@ -480,6 +481,39 @@ Address irgen::emitAddressOfSuperclassRefInClassMetadata(IRGenFunction &IGF,
480481
return IGF.Builder.CreateConstArrayGEP(addr, index, IGF.IGM.getPointerSize());
481482
}
482483

484+
Size irgen::getStaticTupleElementOffset(IRGenModule &IGM,
485+
SILType tupleType,
486+
unsigned eltIdx) {
487+
assert(tupleType.is<TupleType>() && "not a tuple type");
488+
489+
struct TupleElementOffsetScanner
490+
: LayoutScanner<TupleElementOffsetScanner, TupleMetadataScanner> {
491+
private:
492+
using super = LayoutScanner;
493+
494+
// 8 seems a reasonable potential max number tuple elements to start with
495+
llvm::SmallVector<Size, 8> Offsets;
496+
497+
public:
498+
TupleElementOffsetScanner(IRGenModule &IGM, TupleType *const tupleType)
499+
: super(IGM, tupleType) {}
500+
501+
void addElement(unsigned eltIdx, const TupleTypeElt &elt) {
502+
Offsets.push_back(NextOffset);
503+
super::addElement(eltIdx, elt);
504+
}
505+
506+
Size getElementOffset(unsigned eltIdx) const {
507+
return Offsets[eltIdx];
508+
}
509+
};
510+
511+
TupleElementOffsetScanner s(IGM, tupleType.getAs<TupleType>().getPointer());
512+
s.layout();
513+
514+
return s.getElementOffset(eltIdx);
515+
}
516+
483517
/*********************************** ENUMS ************************************/
484518

485519
EnumMetadataLayout::EnumMetadataLayout(IRGenModule &IGM, EnumDecl *decl)

lib/IRGen/MetadataLayout.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,10 @@ llvm::Value *emitClassFieldOffset(IRGenFunction &IGF,
393393
Address emitAddressOfSuperclassRefInClassMetadata(IRGenFunction &IGF,
394394
llvm::Value *metadata);
395395

396+
Size getStaticTupleElementOffset(IRGenModule &IGM,
397+
SILType tupleType,
398+
unsigned eltIdx);
399+
396400
} // end namespace irgen
397401
} // end namespace swift
398402

lib/IRGen/MetadataVisitor.h

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
//===--- MetadataVisitor.h - CRTP for metadata layout -----------*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// A CRTP helper class for preparing the common metadata of all metadata
14+
// objects.
15+
//
16+
//===----------------------------------------------------------------------===//
17+
18+
#ifndef SWIFT_IRGEN_METADATAVISITOR_H
19+
#define SWIFT_IRGEN_METADATAVISITOR_H
20+
21+
namespace swift {
22+
namespace irgen {
23+
24+
/// A CRTP class for laying out a type metadata's common fields. Note that this
25+
/// does *not* handle the metadata template stuff.
26+
template <class Impl> class MetadataVisitor {
27+
protected:
28+
Impl &asImpl() { return *static_cast<Impl*>(this); }
29+
30+
IRGenModule &IGM;
31+
32+
MetadataVisitor(IRGenModule &IGM) : IGM(IGM) {}
33+
34+
public:
35+
void layout() {
36+
// Common fields.
37+
asImpl().addValueWitnessTable();
38+
asImpl().noteAddressPoint();
39+
asImpl().addMetadataFlags();
40+
}
41+
42+
/// This is the address point.
43+
void noteAddressPoint() {}
44+
};
45+
46+
} // end namespace irgen
47+
} // end namespace swift
48+
49+
#endif

lib/IRGen/NominalMetadataVisitor.h

Lines changed: 9 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -18,39 +18,26 @@
1818
#ifndef SWIFT_IRGEN_NOMINALMETADATAVISITOR_H
1919
#define SWIFT_IRGEN_NOMINALMETADATAVISITOR_H
2020

21-
#include "llvm/ADT/SmallVector.h"
22-
#include "swift/AST/Decl.h"
23-
#include "swift/AST/SubstitutionMap.h"
24-
#include "swift/SIL/TypeLowering.h"
2521
#include "GenericRequirement.h"
2622
#include "GenProto.h"
2723
#include "IRGenModule.h"
24+
#include "MetadataVisitor.h"
2825

2926
namespace swift {
3027
namespace irgen {
3128

32-
/// A CRTP class for laying out type metadata. Note that this does
33-
/// *not* handle the metadata template stuff.
34-
template <class Impl> class NominalMetadataVisitor {
35-
protected:
36-
Impl &asImpl() { return *static_cast<Impl*>(this); }
29+
/// A CRTP class for laying out type metadata for nominal types. Note that this
30+
/// does *not* handle the metadata template stuff.
31+
template <class Impl> class NominalMetadataVisitor
32+
: public MetadataVisitor<Impl> {
33+
using super = MetadataVisitor<Impl>;
3734

3835
protected:
39-
IRGenModule &IGM;
36+
using super::asImpl;
4037

41-
NominalMetadataVisitor(IRGenModule &IGM) : IGM(IGM) {}
38+
NominalMetadataVisitor(IRGenModule &IGM) : super(IGM) {}
4239

4340
public:
44-
void layout() {
45-
// Common fields.
46-
asImpl().addValueWitnessTable();
47-
asImpl().noteAddressPoint();
48-
asImpl().addMetadataFlags();
49-
}
50-
51-
/// This is the address point.
52-
void noteAddressPoint() {}
53-
5441
/// Add fields related to the generics of this class declaration.
5542
/// TODO: don't add new fields that are implied by the superclass
5643
/// fields. e.g., if B<T> extends A<T>, the witness for T in A's
@@ -63,7 +50,7 @@ template <class Impl> class NominalMetadataVisitor {
6350
// Note that we intentionally don't std::forward 'args'.
6451
asImpl().noteStartOfGenericRequirements(args...);
6552

66-
GenericTypeRequirements requirements(IGM, typeDecl);
53+
GenericTypeRequirements requirements(super::IGM, typeDecl);
6754
for (auto reqt : requirements.getRequirements()) {
6855
if (reqt.Protocol) {
6956
asImpl().addGenericWitnessTable(args...);

lib/IRGen/TupleMetadataVisitor.h

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
//===--- TupleMetadataVisitor.h - CRTP for tuple metadata ------*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// A CRTP class useful for laying out tuple metadata.
14+
//
15+
//===----------------------------------------------------------------------===//
16+
17+
#ifndef SWIFT_IRGEN_TUPLEMETADATALAYOUT_H
18+
#define SWIFT_IRGEN_TUPLEMETADATALAYOUT_H
19+
20+
//#include "NominalMetadataVisitor.h"
21+
22+
namespace swift {
23+
namespace irgen {
24+
25+
/// A CRTP class for laying out tuple metadata.
26+
///
27+
/// This produces an object corresponding to a TupleTypeMetadata type.
28+
/// It does not itself doing anything special for metadata templates.
29+
template <class Impl> struct TupleMetadataVisitor
30+
: public MetadataVisitor<Impl> {
31+
using super = MetadataVisitor<Impl>;
32+
33+
protected:
34+
using super::asImpl;
35+
36+
TupleType *const Target;
37+
38+
TupleMetadataVisitor(IRGenModule &IGM, TupleType *const target)
39+
: super(IGM), Target(target) {}
40+
41+
public:
42+
void layout() {
43+
super::layout();
44+
45+
asImpl().addNumElementsInfo();
46+
asImpl().addLabelsInfo();
47+
48+
for (unsigned i = 0, n = Target->getNumElements(); i < n; ++i) {
49+
asImpl().addElement(i, Target->getElement(i));
50+
}
51+
}
52+
};
53+
54+
/// An "implementation" of TupleMetadataVisitor that just scans through
55+
/// the metadata layout, maintaining the offset of all tuple elements.
56+
template <class Impl> class TupleMetadataScanner
57+
: public TupleMetadataVisitor<Impl> {
58+
using super = TupleMetadataVisitor<Impl>;
59+
60+
protected:
61+
Size NextOffset = Size(0);
62+
63+
TupleMetadataScanner(IRGenModule &IGM, TupleType *const target)
64+
: super(IGM, target) {}
65+
66+
public:
67+
void addValueWitnessTable() { addPointer(); }
68+
void addMetadataFlags() { addPointer(); }
69+
void addNumElementsInfo() { addPointer(); }
70+
void addLabelsInfo() { addPointer(); }
71+
void addElement(unsigned idx,
72+
const TupleTypeElt &e) { addPointer(); addPointer(); }
73+
74+
private:
75+
void addPointer() { NextOffset += super::IGM.getPointerSize(); }
76+
};
77+
78+
} // end namespace irgen
79+
} // end namespace swift
80+
81+
#endif

0 commit comments

Comments
 (0)