Skip to content

Commit 30afc54

Browse files
authored
Merge pull request #19707 from slavapestov/read-legacy-layout
Add support for reading YAML legacy type info dump
2 parents 0815fd2 + 87ec607 commit 30afc54

File tree

13 files changed

+380
-104
lines changed

13 files changed

+380
-104
lines changed

include/swift/AST/IRGenOptions.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,9 @@ class IRGenOptions {
171171
/// Bypass resilience when accessing resilient frameworks.
172172
unsigned EnableResilienceBypass : 1;
173173

174+
/// The path to load legacy type layouts from.
175+
StringRef ReadTypeInfoPath;
176+
174177
/// Should we try to build incrementally by not emitting an object file if it
175178
/// has the same IR hash as the module that we are preparing to emit?
176179
///

include/swift/Option/FrontendOptions.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -498,6 +498,9 @@ def enable_class_resilience : Flag<["-"], "enable-class-resilience">,
498498
def enable_resilience_bypass : Flag<["-"], "enable-resilience-bypass">,
499499
HelpText<"Completely bypass resilience when accessing types in resilient frameworks">;
500500

501+
def read_type_info_path_EQ : Joined<["-"], "read-type-info-path=">,
502+
HelpText<"Read legacy type layout from the given path">;
503+
501504
def group_info_path : Separate<["-"], "group-info-path">,
502505
HelpText<"The path to collect the group information of the compiled module">;
503506

lib/Frontend/CompilerInvocation.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1023,6 +1023,10 @@ static bool ParseIRGenArgs(IRGenOptions &Opts, ArgList &Args,
10231023
Opts.EnableResilienceBypass = true;
10241024
}
10251025

1026+
if (const Arg *A = Args.getLastArg(OPT_read_type_info_path_EQ)) {
1027+
Opts.ReadTypeInfoPath = A->getValue();
1028+
}
1029+
10261030
for (const auto &Lib : Args.getAllArgValues(options::OPT_autolink_library))
10271031
Opts.LinkLibraries.push_back(LinkLibrary(Lib, LibraryKind::Library));
10281032

lib/IRGen/GenClass.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -373,7 +373,12 @@ namespace {
373373
// Lower the field type.
374374
auto *eltType = &IGM.getTypeInfo(type);
375375
if (CompletelyFragileLayout && !eltType->isFixedSize()) {
376-
CompletelyFragileScope scope(IGM);
376+
// For staging purposes, only do the new thing if the path flag
377+
// is provided.
378+
auto mode = (IGM.IRGen.Opts.ReadTypeInfoPath.empty()
379+
? TypeConverter::Mode::CompletelyFragile
380+
: TypeConverter::Mode::Legacy);
381+
LoweringModeScope scope(IGM, mode);
377382
eltType = &IGM.getTypeInfo(type);
378383
}
379384

lib/IRGen/GenDecl.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1788,7 +1788,7 @@ Address IRGenModule::getAddrOfSILGlobalVariable(SILGlobalVariable *var,
17881788
// FIXME: Once lldb can make use of remote mirrors to calculate layouts
17891789
// at runtime, this should be removed.
17901790
{
1791-
CompletelyFragileScope Scope(*this);
1791+
LoweringModeScope Scope(*this, TypeConverter::Mode::CompletelyFragile);
17921792

17931793
SILType loweredTy = var->getLoweredType();
17941794
auto &nonResilientTI = cast<FixedTypeInfo>(getTypeInfo(loweredTy));
@@ -3602,7 +3602,7 @@ llvm::Constant *IRGenModule::getAddrOfGlobalUTF16String(StringRef utf8) {
36023602
/// of stored properties
36033603
bool IRGenModule::isResilient(NominalTypeDecl *D, ResilienceExpansion expansion) {
36043604
if (expansion == ResilienceExpansion::Maximal &&
3605-
Types.isCompletelyFragile()) {
3605+
Types.getLoweringMode() == TypeConverter::Mode::CompletelyFragile) {
36063606
return false;
36073607
}
36083608
return D->isResilient(getSwiftModule(), expansion);
@@ -3621,7 +3621,7 @@ IRGenModule::getResilienceExpansionForAccess(NominalTypeDecl *decl) {
36213621
// layout. Calling isResilient() with this scope will always return false.
36223622
ResilienceExpansion
36233623
IRGenModule::getResilienceExpansionForLayout(NominalTypeDecl *decl) {
3624-
if (Types.isCompletelyFragile())
3624+
if (Types.getLoweringMode() == TypeConverter::Mode::CompletelyFragile)
36253625
return ResilienceExpansion::Minimal;
36263626

36273627
if (isResilient(decl, ResilienceExpansion::Minimal))

lib/IRGen/GenEnum.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6114,6 +6114,13 @@ const TypeInfo *TypeConverter::convertEnumType(TypeBase *key, CanType type,
61146114
// Assert that the layout query functions for fixed-layout enums work, for
61156115
// LLDB's sake.
61166116
#ifndef NDEBUG
6117+
6118+
// ... but not if we're building a legacy layout, in which case we only know
6119+
// the extra inhabitant *count* and not the actual extra inhabitant values, so
6120+
// we simply crash if we go do this.
6121+
if (LoweringMode == Mode::Legacy)
6122+
return ti;
6123+
61176124
auto displayBitMask = [&](const SpareBitVector &v) {
61186125
for (unsigned i = v.size(); i-- > 0;) {
61196126
llvm::dbgs() << (v[i] ? '1' : '0');

lib/IRGen/GenType.cpp

Lines changed: 155 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include "clang/CodeGen/SwiftCallingConv.h"
3030

3131
#include "EnumPayload.h"
32+
#include "LegacyLayoutFormat.h"
3233
#include "LoadableTypeInfo.h"
3334
#include "GenMeta.h"
3435
#include "GenProto.h"
@@ -56,16 +57,10 @@ Alignment IRGenModule::getCappedAlignment(Alignment align) {
5657
}
5758

5859
llvm::DenseMap<TypeBase *, const TypeInfo *> &
59-
TypeConverter::Types_t::getCacheFor(bool isDependent, bool completelyFragile) {
60-
if (completelyFragile) {
61-
return (isDependent
62-
? FragileDependentCache
63-
: FragileIndependentCache);
64-
}
65-
60+
TypeConverter::Types_t::getCacheFor(bool isDependent, TypeConverter::Mode mode) {
6661
return (isDependent
67-
? DependentCache
68-
: IndependentCache);
62+
? DependentCache[unsigned(mode)]
63+
: IndependentCache[unsigned(mode)]);
6964
}
7065

7166
void TypeInfo::assign(IRGenFunction &IGF, Address dest, Address src,
@@ -1071,6 +1066,54 @@ TypeConverter::createImmovable(llvm::Type *type, Size size, Alignment align) {
10711066

10721067
static TypeInfo *invalidTypeInfo() { return (TypeInfo*) 1; }
10731068

1069+
bool TypeConverter::readLegacyTypeInfo(StringRef path) {
1070+
auto fileOrErr = llvm::MemoryBuffer::getFile(path);
1071+
if (!fileOrErr)
1072+
return true;
1073+
1074+
auto file = std::move(fileOrErr.get());
1075+
1076+
llvm::yaml::Input yin(file->getBuffer());
1077+
1078+
// Read the document list.
1079+
std::vector<YAMLModuleNode> modules;
1080+
yin >> modules;
1081+
1082+
if (yin.error())
1083+
return true;
1084+
1085+
for (auto &module : modules) {
1086+
for (auto &decl : module.Decls) {
1087+
auto result = LegacyTypeInfos.insert(std::make_pair(
1088+
decl.Name,
1089+
decl));
1090+
assert(result.second);
1091+
(void) result;
1092+
}
1093+
}
1094+
1095+
return false;
1096+
}
1097+
1098+
static std::string mangleTypeAsContext(const NominalTypeDecl *decl) {
1099+
Mangle::ASTMangler Mangler;
1100+
return Mangler.mangleTypeAsContextUSR(decl);
1101+
}
1102+
1103+
Optional<YAMLTypeInfoNode>
1104+
TypeConverter::getLegacyTypeInfo(NominalTypeDecl *decl) const {
1105+
auto &mangledName = const_cast<TypeConverter *>(this)->DeclMangledNames[decl];
1106+
if (mangledName.empty())
1107+
mangledName = mangleTypeAsContext(decl);
1108+
assert(!mangledName.empty());
1109+
1110+
auto found = LegacyTypeInfos.find(mangledName);
1111+
if (found == LegacyTypeInfos.end())
1112+
return None;
1113+
1114+
return found->second;
1115+
}
1116+
10741117
TypeConverter::TypeConverter(IRGenModule &IGM)
10751118
: IGM(IGM),
10761119
FirstType(invalidTypeInfo()) {
@@ -1080,7 +1123,15 @@ TypeConverter::TypeConverter(IRGenModule &IGM)
10801123
// sync with the binary module. Once LLDB can calculate type layouts at
10811124
// runtime (using remote mirrors or some other mechanism), we can remove this.
10821125
if (IGM.IRGen.Opts.EnableResilienceBypass)
1083-
CompletelyFragile = true;
1126+
LoweringMode = Mode::CompletelyFragile;
1127+
1128+
StringRef path = IGM.IRGen.Opts.ReadTypeInfoPath;
1129+
if (!path.empty()) {
1130+
bool error = readLegacyTypeInfo(path);
1131+
if (error) {
1132+
llvm::report_fatal_error("Cannot read '" + path + "'");
1133+
}
1134+
}
10841135
}
10851136

10861137
TypeConverter::~TypeConverter() {
@@ -1102,8 +1153,9 @@ void TypeConverter::pushGenericContext(CanGenericSignature signature) {
11021153

11031154
// Clear the dependent type info cache since we have a new active signature
11041155
// now.
1105-
Types.getCacheFor(/*isDependent*/ true, /*isFragile*/ false).clear();
1106-
Types.getCacheFor(/*isDependent*/ true, /*isFragile*/ true).clear();
1156+
Types.getCacheFor(/*isDependent*/ true, Mode::Normal).clear();
1157+
Types.getCacheFor(/*isDependent*/ true, Mode::Legacy).clear();
1158+
Types.getCacheFor(/*isDependent*/ true, Mode::CompletelyFragile).clear();
11071159
}
11081160

11091161
void TypeConverter::popGenericContext(CanGenericSignature signature) {
@@ -1113,8 +1165,9 @@ void TypeConverter::popGenericContext(CanGenericSignature signature) {
11131165
// Pop the SIL TypeConverter's generic context too.
11141166
IGM.getSILTypes().popGenericContext(signature);
11151167

1116-
Types.getCacheFor(/*isDependent*/ true, /*isFragile*/ false).clear();
1117-
Types.getCacheFor(/*isDependent*/ true, /*isFragile*/ true).clear();
1168+
Types.getCacheFor(/*isDependent*/ true, Mode::Normal).clear();
1169+
Types.getCacheFor(/*isDependent*/ true, Mode::Legacy).clear();
1170+
Types.getCacheFor(/*isDependent*/ true, Mode::CompletelyFragile).clear();
11181171
}
11191172

11201173
GenericEnvironment *TypeConverter::getGenericEnvironment() {
@@ -1131,7 +1184,7 @@ GenericEnvironment *IRGenModule::getGenericEnvironment() {
11311184
void TypeConverter::addForwardDecl(TypeBase *key) {
11321185
assert(key->isCanonical());
11331186
assert(!key->hasTypeParameter());
1134-
auto &Cache = Types.getCacheFor(/*isDependent*/ false, CompletelyFragile);
1187+
auto &Cache = Types.getCacheFor(/*isDependent*/ false, LoweringMode);
11351188
auto result = Cache.insert(std::make_pair(key, nullptr));
11361189
assert(result.second && "entry already exists for type!");
11371190
(void) result;
@@ -1409,20 +1462,10 @@ CanType TypeConverter::getExemplarType(CanType contextTy) {
14091462
}
14101463
}
14111464

1412-
void TypeConverter::pushCompletelyFragile() {
1413-
assert(!CompletelyFragile);
1414-
CompletelyFragile = true;
1415-
}
1416-
1417-
void TypeConverter::popCompletelyFragile() {
1418-
assert(CompletelyFragile);
1419-
CompletelyFragile = false;
1420-
}
1421-
14221465
const TypeInfo *TypeConverter::getTypeEntry(CanType canonicalTy) {
14231466
// Cache this entry in the dependent or independent cache appropriate to it.
14241467
auto &Cache = Types.getCacheFor(canonicalTy->hasTypeParameter(),
1425-
CompletelyFragile);
1468+
LoweringMode);
14261469

14271470
{
14281471
auto it = Cache.find(canonicalTy.getPointer());
@@ -1447,7 +1490,7 @@ const TypeInfo *TypeConverter::getTypeEntry(CanType canonicalTy) {
14471490

14481491
// See whether we lowered a type equivalent to this one.
14491492
if (exemplarTy != canonicalTy) {
1450-
auto &Cache = Types.getCacheFor(/*isDependent*/ false, CompletelyFragile);
1493+
auto &Cache = Types.getCacheFor(/*isDependent*/ false, LoweringMode);
14511494
auto it = Cache.find(exemplarTy.getPointer());
14521495
if (it != Cache.end()) {
14531496
// Record the object under the original type.
@@ -1469,7 +1512,7 @@ const TypeInfo *TypeConverter::getTypeEntry(CanType canonicalTy) {
14691512
insertEntry(Cache[canonicalTy.getPointer()]);
14701513
if (canonicalTy != exemplarTy) {
14711514
auto &IndependentCache = Types.getCacheFor(/*isDependent*/ false,
1472-
CompletelyFragile);
1515+
LoweringMode);
14731516
insertEntry(IndependentCache[exemplarTy.getPointer()]);
14741517
}
14751518

@@ -1809,11 +1852,94 @@ static bool isIRTypeDependent(IRGenModule &IGM, NominalTypeDecl *decl) {
18091852
}
18101853
}
18111854

1855+
namespace {
1856+
1857+
class LegacyTypeInfo : public FixedTypeInfo {
1858+
unsigned NumExtraInhabitants;
1859+
1860+
public:
1861+
LegacyTypeInfo(llvm::Type *type, const SpareBitVector &spareBits,
1862+
const YAMLTypeInfoNode &node)
1863+
: FixedTypeInfo(type,
1864+
Size(node.Size),
1865+
spareBits,
1866+
Alignment(node.Alignment),
1867+
IsNotPOD, /* irrelevant */
1868+
IsNotBitwiseTakable, /* irrelevant */
1869+
IsFixedSize /* irrelevant */),
1870+
NumExtraInhabitants(node.NumExtraInhabitants) {}
1871+
1872+
virtual unsigned getFixedExtraInhabitantCount(IRGenModule &IGM) const override {
1873+
return NumExtraInhabitants;
1874+
}
1875+
1876+
virtual APInt getFixedExtraInhabitantMask(IRGenModule &IGM) const override {
1877+
llvm_unreachable("TypeConverter::Mode::Legacy is not for real values");
1878+
}
1879+
1880+
virtual APInt getFixedExtraInhabitantValue(IRGenModule &IGM,
1881+
unsigned bits,
1882+
unsigned index) const override {
1883+
llvm_unreachable("TypeConverter::Mode::Legacy is not for real values");
1884+
}
1885+
1886+
virtual void getSchema(ExplosionSchema &schema) const override {
1887+
llvm_unreachable("TypeConverter::Mode::Legacy is not for real values");
1888+
}
1889+
1890+
virtual void assignWithCopy(IRGenFunction &IGF, Address dest, Address src,
1891+
SILType T, bool isOutlined) const override {
1892+
llvm_unreachable("TypeConverter::Mode::Legacy is not for real values");
1893+
}
1894+
1895+
virtual void assignWithTake(IRGenFunction &IGF, Address dest, Address src,
1896+
SILType T, bool isOutlined) const override {
1897+
llvm_unreachable("TypeConverter::Mode::Legacy is not for real values");
1898+
}
1899+
1900+
virtual void initializeWithCopy(IRGenFunction &IGF, Address destAddr,
1901+
Address srcAddr, SILType T,
1902+
bool isOutlined) const override {
1903+
llvm_unreachable("TypeConverter::Mode::Legacy is not for real values");
1904+
}
1905+
1906+
virtual void initializeFromParams(IRGenFunction &IGF, Explosion &params,
1907+
Address src, SILType T,
1908+
bool isOutlined) const override {
1909+
llvm_unreachable("TypeConverter::Mode::Legacy is not for real values");
1910+
}
1911+
1912+
virtual void destroy(IRGenFunction &IGF, Address address, SILType T,
1913+
bool isOutlined) const override {
1914+
llvm_unreachable("TypeConverter::Mode::Legacy is not for real values");
1915+
}
1916+
};
1917+
1918+
} // namespace
1919+
18121920
const TypeInfo *TypeConverter::convertAnyNominalType(CanType type,
18131921
NominalTypeDecl *decl) {
18141922
// By "any", we don't mean existentials.
18151923
assert(!isa<ProtocolDecl>(decl));
18161924

1925+
// If we're producing a legacy type layout, and we have a serialized
1926+
// record for this type, produce it now.
1927+
if (LoweringMode == Mode::Legacy) {
1928+
auto node = getLegacyTypeInfo(decl);
1929+
1930+
if (node) {
1931+
Size size(node->Size);
1932+
1933+
auto ty = IGM.createNominalType(type);
1934+
ty->setBody(llvm::ArrayType::get(IGM.Int8Ty, size.getValue()));
1935+
1936+
SpareBitVector spareBits;
1937+
spareBits.appendClearBits(size.getValueInBits());
1938+
1939+
return new LegacyTypeInfo(ty, spareBits, *node);
1940+
}
1941+
}
1942+
18171943
// We need to give generic specializations distinct TypeInfo objects
18181944
// if their IR-gen might be different, e.g. if they use different IR
18191945
// types or if type-specific operations like projections might need
@@ -1849,7 +1975,7 @@ const TypeInfo *TypeConverter::convertAnyNominalType(CanType type,
18491975
assert(decl->getDeclaredType()->isCanonical());
18501976
assert(decl->getDeclaredType()->hasUnboundGenericType());
18511977
TypeBase *key = decl->getDeclaredType().getPointer();
1852-
auto &Cache = Types.getCacheFor(/*isDependent*/ false, CompletelyFragile);
1978+
auto &Cache = Types.getCacheFor(/*isDependent*/ false, LoweringMode);
18531979
auto entry = Cache.find(key);
18541980
if (entry != Cache.end())
18551981
return entry->second;

0 commit comments

Comments
 (0)