Skip to content

Commit bc97405

Browse files
committed
Use on-disk hash table to serialize and deserialize availability domain
information rdar://147122406
1 parent fcec10c commit bc97405

File tree

15 files changed

+293
-9
lines changed

15 files changed

+293
-9
lines changed

clang/include/clang/AST/ExternalASTSource.h

+5
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,11 @@ class ExternalASTSource : public RefCountedBase<ExternalASTSource> {
142142
/// Update an out-of-date identifier.
143143
virtual void updateOutOfDateIdentifier(const IdentifierInfo &II) {}
144144

145+
// Retrieve the variable declaration that has the information for the domain.
146+
virtual Decl *getAvailabilityDomainDecl(StringRef DomainName) {
147+
return nullptr;
148+
}
149+
145150
/// Find all declarations with the given name in the given context,
146151
/// and add them to the context by calling SetExternalVisibleDeclsForName
147152
/// or SetNoExternalVisibleDeclsForName.

clang/include/clang/Serialization/ASTBitCodes.h

+3
Original file line numberDiff line numberDiff line change
@@ -738,6 +738,9 @@ enum ASTRecordTypes {
738738
/// Record code for Sema's vector of functions/blocks with effects to
739739
/// be verified.
740740
DECLS_WITH_EFFECTS_TO_VERIFY = 72,
741+
742+
/// Record code for availability domain table.
743+
AVAILABILITY_DOMAIN_TABLE = 73,
741744
};
742745

743746
/// Record types used within a source manager block.

clang/include/clang/Serialization/ASTReader.h

+1
Original file line numberDiff line numberDiff line change
@@ -1445,6 +1445,7 @@ class ASTReader
14451445
ASTReaderListener *Listener,
14461446
bool ValidateDiagnosticOptions);
14471447

1448+
Decl *getAvailabilityDomainDecl(StringRef DomainName) override;
14481449
llvm::Error ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities);
14491450
llvm::Error ReadExtensionBlock(ModuleFile &F);
14501451
void ReadModuleOffsetMap(ModuleFile &F) const;

clang/include/clang/Serialization/ASTWriter.h

+1
Original file line numberDiff line numberDiff line change
@@ -569,6 +569,7 @@ class ASTWriter : public ASTDeserializationListener,
569569
uint64_t WriteDeclContextLexicalBlock(ASTContext &Context,
570570
const DeclContext *DC);
571571
uint64_t WriteDeclContextVisibleBlock(ASTContext &Context, DeclContext *DC);
572+
void writeAvailabilityDomainDecls(ASTContext &Context);
572573
void WriteTypeDeclOffsets();
573574
void WriteFileDeclIDsMap();
574575
void WriteComments(ASTContext &Context);

clang/include/clang/Serialization/ModuleFile.h

+4
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,10 @@ class ModuleFile {
405405
/// the header files.
406406
void *HeaderFileInfoTable = nullptr;
407407

408+
/// The on-disk hash table that contains information about availability
409+
/// domains.
410+
void *AvailabilityDomainTable = nullptr;
411+
408412
// === Submodule information ===
409413

410414
/// The number of submodules in this module.

clang/lib/AST/ASTContext.cpp

+7-5
Original file line numberDiff line numberDiff line change
@@ -908,9 +908,15 @@ ASTContext::getFeatureAvailInfo(StringRef FeatureName) const {
908908
if (Kind != FeatureAvailKind::None)
909909
return {Kind};
910910

911+
Decl *D = nullptr;
911912
auto I = AvailabilityDomainMap.find(FeatureName);
912913
if (I != AvailabilityDomainMap.end())
913-
return getFeatureAvailInfo(I->second).second;
914+
D = I->second;
915+
else if (auto *Source = getExternalSource())
916+
D = Source->getAvailabilityDomainDecl(FeatureName);
917+
918+
if (D)
919+
return getFeatureAvailInfo(D).second;
914920

915921
return {};
916922
}
@@ -13214,10 +13220,6 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) {
1321413220
const auto *VD = cast<VarDecl>(D);
1321513221
assert(VD->isFileVarDecl() && "Expected file scoped var");
1321613222

13217-
// Variables annotated with availability_domain need to be deserialized.
13218-
if (VD->hasAttr<AvailabilityDomainAttr>())
13219-
return true;
13220-
1322113223
// If the decl is marked as `declare target to`, it should be emitted for the
1322213224
// host and for the device.
1322313225
if (LangOpts.OpenMP &&

clang/lib/Serialization/ASTReader.cpp

+76
Original file line numberDiff line numberDiff line change
@@ -3279,6 +3279,74 @@ ASTReader::ReadControlBlock(ModuleFile &F,
32793279
}
32803280
}
32813281

3282+
AvailabilityDomainsTableReaderTrait::hash_value_type
3283+
AvailabilityDomainsTableReaderTrait::ComputeHash(internal_key_type Key) {
3284+
return llvm::djbHash(Key);
3285+
}
3286+
3287+
std::pair<unsigned, unsigned>
3288+
AvailabilityDomainsTableReaderTrait::ReadKeyDataLength(const uint8_t *&Data) {
3289+
unsigned KeyLength =
3290+
llvm::support::endian::readNext<uint16_t, llvm::endianness::little>(Data);
3291+
unsigned DataLength =
3292+
llvm::support::endian::readNext<uint16_t, llvm::endianness::little>(Data);
3293+
return {KeyLength, DataLength};
3294+
}
3295+
3296+
AvailabilityDomainsTableReaderTrait::internal_key_type
3297+
AvailabilityDomainsTableReaderTrait::ReadKey(const uint8_t *Data,
3298+
unsigned Length) {
3299+
return llvm::StringRef(reinterpret_cast<const char *>(Data), Length);
3300+
}
3301+
3302+
AvailabilityDomainsTableReaderTrait::data_type
3303+
AvailabilityDomainsTableReaderTrait::ReadData(internal_key_type Key,
3304+
const uint8_t *Data,
3305+
unsigned Length) {
3306+
return llvm::support::endian::readNext<data_type, llvm::endianness::little>(
3307+
Data);
3308+
}
3309+
3310+
class AvailabilityDomainVisitor {
3311+
std::optional<Decl *> D;
3312+
StringRef DomainName;
3313+
ASTReader &Reader;
3314+
3315+
public:
3316+
explicit AvailabilityDomainVisitor(StringRef DomainName, ASTReader &Reader)
3317+
: DomainName(DomainName), Reader(Reader) {}
3318+
3319+
bool operator()(ModuleFile &M) {
3320+
AvailabilityDomainLookupTable *Table =
3321+
static_cast<AvailabilityDomainLookupTable *>(M.AvailabilityDomainTable);
3322+
3323+
if (!Table)
3324+
return false;
3325+
3326+
// Look in the on-disk hash table for an entry for this domain name.
3327+
AvailabilityDomainLookupTable::iterator Pos = Table->find(DomainName);
3328+
if (Pos == Table->end())
3329+
return false;
3330+
3331+
LocalDeclID LocalID = LocalDeclID::get(Reader, M, *Pos);
3332+
GlobalDeclID ID = Reader.getGlobalDeclID(M, LocalID);
3333+
D = Reader.GetDecl(ID);
3334+
return true;
3335+
}
3336+
3337+
std::optional<Decl *> getDecl() const { return D; }
3338+
};
3339+
3340+
Decl *ASTReader::getAvailabilityDomainDecl(StringRef DomainName) {
3341+
AvailabilityDomainVisitor Visitor(DomainName, *this);
3342+
ModuleMgr.visit(Visitor);
3343+
3344+
if (std::optional<Decl *> D = Visitor.getDecl())
3345+
return *D;
3346+
3347+
return nullptr;
3348+
}
3349+
32823350
llvm::Error ASTReader::ReadASTBlock(ModuleFile &F,
32833351
unsigned ClientLoadCapabilities) {
32843352
BitstreamCursor &Stream = F.Stream;
@@ -3565,6 +3633,14 @@ llvm::Error ASTReader::ReadASTBlock(ModuleFile &F,
35653633
UnusedFileScopedDecls.push_back(ReadDeclID(F, Record, I));
35663634
break;
35673635

3636+
case AVAILABILITY_DOMAIN_TABLE: {
3637+
auto Data = Blob.data();
3638+
F.AvailabilityDomainTable = AvailabilityDomainLookupTable::Create(
3639+
(const unsigned char *)Data + Record[0], (const unsigned char *)Data,
3640+
AvailabilityDomainsTableReaderTrait());
3641+
break;
3642+
}
3643+
35683644
case DELEGATING_CTORS:
35693645
for (unsigned I = 0, N = Record.size(); I != N; /*in loop*/)
35703646
DelegatingCtorDecls.push_back(ReadDeclID(F, Record, I));

clang/lib/Serialization/ASTReaderDecl.cpp

-4
Original file line numberDiff line numberDiff line change
@@ -1683,10 +1683,6 @@ ASTDeclReader::RedeclarableResult ASTDeclReader::VisitVarDeclImpl(VarDecl *VD) {
16831683
}
16841684
}
16851685

1686-
if (auto *Attr = VD->getAttr<AvailabilityDomainAttr>())
1687-
Reader.getContext().addAvailabilityDomainMap(Attr->getName()->getName(),
1688-
VD);
1689-
16901686
return Redecl;
16911687
}
16921688

clang/lib/Serialization/ASTReaderInternals.h

+32
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,38 @@ class HeaderFileInfoTrait {
282282
using HeaderFileInfoLookupTable =
283283
llvm::OnDiskChainedHashTable<HeaderFileInfoTrait>;
284284

285+
/// This trait class is used for searching the on-disk hash table that stores
286+
/// feature availability information. The hash table maps feature names to Decl
287+
/// IDs that corresponds to the variables declared in header files.
288+
class AvailabilityDomainsTableReaderTrait {
289+
public:
290+
using internal_key_type = llvm::StringRef;
291+
using external_key_type = internal_key_type;
292+
using data_type = clang::serialization::DeclID;
293+
using hash_value_type = uint32_t;
294+
using offset_type = unsigned;
295+
296+
internal_key_type GetInternalKey(external_key_type Key) { return Key; }
297+
external_key_type GetExternalKey(internal_key_type Key) { return Key; }
298+
299+
hash_value_type ComputeHash(internal_key_type Key);
300+
301+
static bool EqualKey(internal_key_type LHS, internal_key_type RHS) {
302+
return LHS == RHS;
303+
}
304+
305+
static std::pair<unsigned, unsigned> ReadKeyDataLength(const uint8_t *&Data);
306+
307+
static internal_key_type ReadKey(const uint8_t *Data, unsigned Length);
308+
309+
static data_type ReadData(internal_key_type Key, const uint8_t *Data,
310+
unsigned Length);
311+
};
312+
313+
/// The on-disk hash table used for availability domain lookup.
314+
using AvailabilityDomainLookupTable =
315+
llvm::OnDiskChainedHashTable<AvailabilityDomainsTableReaderTrait>;
316+
285317
} // namespace reader
286318

287319
} // namespace serialization

clang/lib/Serialization/ASTWriter.cpp

+73
Original file line numberDiff line numberDiff line change
@@ -941,6 +941,7 @@ void ASTWriter::WriteBlockInfoBlock() {
941941
RECORD(PP_ASSUME_NONNULL_LOC);
942942
RECORD(PP_UNSAFE_BUFFER_USAGE);
943943
RECORD(VTABLES_TO_EMIT);
944+
RECORD(AVAILABILITY_DOMAIN_TABLE);
944945

945946
// SourceManager Block.
946947
BLOCK(SOURCE_MANAGER_BLOCK);
@@ -3392,6 +3393,76 @@ uint64_t ASTWriter::WriteDeclContextLexicalBlock(ASTContext &Context,
33923393
return Offset;
33933394
}
33943395

3396+
namespace {
3397+
class AvailabilityDomainsTableTrait {
3398+
public:
3399+
using key_type = StringRef;
3400+
using key_type_ref = key_type;
3401+
using data_type = clang::serialization::DeclID;
3402+
using data_type_ref = const data_type &;
3403+
using hash_value_type = uint32_t;
3404+
using offset_type = unsigned;
3405+
3406+
hash_value_type ComputeHash(key_type_ref Key) { return llvm::djbHash(Key); }
3407+
3408+
std::pair<unsigned, unsigned>
3409+
EmitKeyDataLength(raw_ostream &Out, key_type_ref Key, data_type_ref) {
3410+
uint32_t KeyLength = Key.size();
3411+
uint32_t DataLength = sizeof(data_type);
3412+
3413+
llvm::support::endian::Writer Writer(Out, llvm::endianness::little);
3414+
Writer.write<uint16_t>(KeyLength);
3415+
Writer.write<uint16_t>(DataLength);
3416+
return {KeyLength, DataLength};
3417+
}
3418+
3419+
void EmitKey(raw_ostream &Out, key_type_ref Key, unsigned) { Out << Key; }
3420+
3421+
void EmitData(raw_ostream &Out, key_type_ref, data_type_ref Data, unsigned) {
3422+
llvm::support::endian::Writer writer(Out, llvm::endianness::little);
3423+
writer.write<data_type>(Data);
3424+
}
3425+
};
3426+
} // namespace
3427+
3428+
void ASTWriter::writeAvailabilityDomainDecls(ASTContext &Context) {
3429+
using namespace llvm;
3430+
if (Context.AvailabilityDomainMap.empty())
3431+
return;
3432+
3433+
AvailabilityDomainsTableTrait GeneratorTrait;
3434+
llvm::OnDiskChainedHashTableGenerator<AvailabilityDomainsTableTrait>
3435+
Generator;
3436+
3437+
for (auto &P : Context.AvailabilityDomainMap)
3438+
Generator.insert(P.first, GetDeclRef(P.second).getRawValue(),
3439+
GeneratorTrait);
3440+
3441+
// Create the on-disk hash table in a buffer.
3442+
SmallString<4096> AvailDomainTable;
3443+
uint32_t BucketOffset;
3444+
{
3445+
using namespace llvm::support;
3446+
llvm::raw_svector_ostream Out(AvailDomainTable);
3447+
// Make sure that no bucket is at offset 0
3448+
endian::write<uint32_t>(Out, 0, llvm::endianness::little);
3449+
BucketOffset = Generator.Emit(Out, GeneratorTrait);
3450+
}
3451+
3452+
// Create a blob abbreviation.
3453+
auto Abbrev = std::make_shared<BitCodeAbbrev>();
3454+
Abbrev->Add(BitCodeAbbrevOp(AVAILABILITY_DOMAIN_TABLE));
3455+
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
3456+
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
3457+
unsigned MethodPoolAbbrev = Stream.EmitAbbrev(std::move(Abbrev));
3458+
3459+
// Write the table.
3460+
{
3461+
RecordData::value_type Record[] = {AVAILABILITY_DOMAIN_TABLE, BucketOffset};
3462+
Stream.EmitRecordWithBlob(MethodPoolAbbrev, Record, AvailDomainTable);
3463+
}
3464+
}
3465+
33953466
void ASTWriter::WriteTypeDeclOffsets() {
33963467
using namespace llvm;
33973468

@@ -5798,6 +5869,8 @@ void ASTWriter::WriteDeclAndTypes(ASTContext &Context) {
57985869
// Write the visible updates to DeclContexts.
57995870
for (auto *DC : UpdatedDeclContexts)
58005871
WriteDeclContextVisibleUpdate(Context, DC);
5872+
5873+
writeAvailabilityDomainDecls(Context);
58015874
}
58025875

58035876
void ASTWriter::WriteDeclUpdatesBlocks(ASTContext &Context,

clang/test/CodeGen/feature-availability.c

+3
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
// RUN: %clang_cc1 -triple arm64-apple-macosx -fblocks -ffeature-availability=feature1:on -ffeature-availability=feature2:off -emit-pch -o %t %s
55
// RUN: %clang_cc1 -triple arm64-apple-macosx -fblocks -ffeature-availability=feature1:on -ffeature-availability=feature2:off -include-pch %t -emit-llvm -o - %s | FileCheck %s
66

7+
// RUN: %clang_cc1 -triple arm64-apple-macosx -fblocks -emit-pch -o %t -DUSE_DOMAIN %s
8+
// RUN: %clang_cc1 -triple arm64-apple-macosx -fblocks -include-pch %t -emit-llvm -o - -DUSE_DOMAIN %s | FileCheck --check-prefixes=CHECK,DOMAIN %s
9+
710
// CHECK: %[[STRUCT_S0:.*]] = type { i32 }
811
// CHECK: @g0 = external global i32, align 4
912
// CHECK-NOT: @g1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#ifndef FEATURE1_H
2+
#define FEATURE1_H
3+
#include <feature-availability.h>
4+
5+
static struct __AvailabilityDomain feature1 __attribute__((availability_domain(feature1))) = {__AVAILABILITY_DOMAIN_ENABLED, 0};
6+
7+
#endif
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#ifndef FEATURE2_H
2+
#define FEATURE2_H
3+
#include <feature-availability.h>
4+
#include "feature1.h"
5+
6+
static struct __AvailabilityDomain feature2 __attribute__((availability_domain(feature2))) = {__AVAILABILITY_DOMAIN_DISABLED, 0};
7+
8+
#endif
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
module Feature1 {
2+
header "feature1.h"
3+
export *
4+
}
5+
6+
module Feature2 {
7+
header "feature2.h"
8+
export *
9+
}

0 commit comments

Comments
 (0)