uint32_t getIndex() const { return Idx; }
TypeID asTypeID(unsigned FastQuals) const {
+ if (Idx == uint32_t(-1))
+ return TypeID(-1);
+
return (Idx << Qualifiers::FastWidth) | FastQuals;
}
static TypeIdx fromTypeID(TypeID ID) {
+ if (ID == TypeID(-1))
+ return TypeIdx(-1);
+
return TypeIdx(ID >> Qualifiers::FastWidth);
}
};
/// type ID, or the representation of a Type*.
const uint32_t *TypeOffsets;
- /// \brief Base type ID for types local to this module.
- serialization::TypeID BaseTypeID;
-
+ /// \brief Base type ID for types local to this module as represented in
+ /// the global type ID space.
+ serialization::TypeID GlobalBaseTypeIndex;
+
+ /// \brief Remapping table for type IDs in this module.
+ ContinuousRangeMap<uint32_t, int, 2> TypeRemap;
+
+ /// \brief Base type ID for types local to this module as represented in
+ /// the module's type ID space.
+ serialization::TypeID LocalBaseTypeIndex;
+
+ /// \brief Remapping table that maps from a type as represented as a module
+ /// and local type index to the index used within the current module to
+ /// refer to that same type.
+ ///
+ /// This mapping is effectively the reverse of the normal \c TypeRemap, and
+ /// is used specifically by ASTReader::GetTypeIdx() to help map between
+ /// global type IDs and a module's view of the same type ID as a hash value.
+ llvm::DenseMap<Module *, int> ReverseTypeRemap;
+
// === Miscellaneous ===
/// \brief Diagnostic IDs and their mappings that the user changed.
/// \brief Map a local type ID within a given AST file into a global type ID.
serialization::TypeID getGlobalTypeID(Module &F, unsigned LocalID) const;
+ /// \brief Map a global type ID to an ID as it would be locally expressed
+ /// in the given model.
+ unsigned getLocalTypeID(Module &M, serialization::TypeID GlobalID);
+
/// \brief Read a type from the current position in the given record, which
/// was read from the given AST file.
QualType readType(Module &F, const RecordData &Record, unsigned &Idx) {
template <typename Int, typename V, unsigned InitialCapacity>
class ContinuousRangeMap {
public:
- typedef std::pair<const Int, V> value_type;
+ typedef std::pair<Int, V> value_type;
typedef value_type &reference;
typedef const value_type &const_reference;
typedef value_type *pointer;
/// from a set of values.
class Builder {
ContinuousRangeMap &Self;
- SmallVector<std::pair<Int, V>, InitialCapacity> Elements;
Builder(const Builder&); // DO NOT IMPLEMENT
Builder &operator=(const Builder&); // DO NOT IMPLEMENT
explicit Builder(ContinuousRangeMap &Self) : Self(Self) { }
~Builder() {
- std::sort(Elements.begin(), Elements.end(), Compare());
- for (unsigned I = 0, N = Elements.size(); I != N; ++I)
- Self.insert(Elements[I]);
+ std::sort(Self.Rep.begin(), Self.Rep.end(), Compare());
}
void insert(const value_type &Val) {
- Elements.push_back(Val);
+ Self.Rep.push_back(Val);
}
};
friend class Builder;
case DeclarationName::CXXConstructorName:
case DeclarationName::CXXDestructorName:
case DeclarationName::CXXConversionFunctionName:
- ID.AddInteger((TypeID)Key.Data);
+ if (TypeID(Key.Data) == TypeID(-1))
+ ID.AddInteger((TypeID)Key.Data);
+ else
+ ID.AddInteger(Reader.getLocalTypeID(F, (TypeID)Key.Data));
break;
case DeclarationName::CXXOperatorName:
ID.AddInteger((OverloadedOperatorKind)Key.Data);
break;
}
- case TYPE_OFFSET:
+ case TYPE_OFFSET: {
if (F.LocalNumTypes != 0) {
Error("duplicate TYPE_OFFSET record in AST file");
return Failure;
}
F.TypeOffsets = (const uint32_t *)BlobStart;
F.LocalNumTypes = Record[0];
- F.BaseTypeID = getTotalNumTypes();
+ F.LocalBaseTypeIndex = Record[1];
+ F.GlobalBaseTypeIndex = getTotalNumTypes();
- // Introduce the global -> local mapping for types within this
- // AST file.
- GlobalTypeMap.insert(std::make_pair(getTotalNumTypes() + 1, &F));
- TypesLoaded.resize(TypesLoaded.size() + F.LocalNumTypes);
+ if (F.LocalNumTypes > 0) {
+ // Introduce the global -> local mapping for types within this module.
+ GlobalTypeMap.insert(std::make_pair(getTotalNumTypes(), &F));
+
+ // Introduce the local -> global mapping for types within this module.
+ F.TypeRemap.insert(std::make_pair(F.LocalBaseTypeIndex,
+ F.GlobalBaseTypeIndex - F.LocalBaseTypeIndex));
+
+ TypesLoaded.resize(TypesLoaded.size() + F.LocalNumTypes);
+ }
break;
-
+ }
+
case DECL_OFFSET:
if (F.LocalNumDecls != 0) {
Error("duplicate DECL_OFFSET record in AST file");
// Continuous range maps we may be updating in our module.
ContinuousRangeMap<uint32_t, int, 2>::Builder SLocRemap(F.SLocRemap);
-
+ ContinuousRangeMap<uint32_t, int, 2>::Builder TypeRemap(F.TypeRemap);
+
while(Data < DataEnd) {
uint16_t Len = io::ReadUnalignedLE16(Data);
StringRef Name = StringRef((const char*)Data, Len);
uint32_t SelectorIDOffset = io::ReadUnalignedLE32(Data);
uint32_t DeclIDOffset = io::ReadUnalignedLE32(Data);
uint32_t CXXBaseSpecifiersIDOffset = io::ReadUnalignedLE32(Data);
- uint32_t TypeIDOffset = io::ReadUnalignedLE32(Data);
+ uint32_t TypeIndexOffset = io::ReadUnalignedLE32(Data);
// Source location offset is mapped to OM->SLocEntryBaseOffset.
SLocRemap.insert(std::make_pair(SLocOffset,
(void)SelectorIDOffset;
(void)DeclIDOffset;
(void)CXXBaseSpecifiersIDOffset;
- (void)TypeIDOffset;
+
+ TypeRemap.insert(std::make_pair(TypeIndexOffset,
+ OM->GlobalBaseTypeIndex - TypeIndexOffset));
+ F.ReverseTypeRemap[OM] = TypeIndexOffset - OM->GlobalBaseTypeIndex;
}
break;
}
/// \brief Get the correct cursor and offset for loading a type.
ASTReader::RecordLocation ASTReader::TypeCursorForIndex(unsigned Index) {
- GlobalTypeMapType::iterator I = GlobalTypeMap.find(Index+1);
+ GlobalTypeMapType::iterator I = GlobalTypeMap.find(Index);
assert(I != GlobalTypeMap.end() && "Corrupted global type map");
Module *M = I->second;
- return RecordLocation(M, M->TypeOffsets[Index - M->BaseTypeID]);
+ return RecordLocation(M, M->TypeOffsets[Index - M->GlobalBaseTypeIndex]);
}
/// \brief Read and return the type with the given index..
serialization::TypeID
ASTReader::getGlobalTypeID(Module &F, unsigned LocalID) const {
- // FIXME: Map from local type ID to global type ID.
- return LocalID;
+ unsigned FastQuals = LocalID & Qualifiers::FastMask;
+ unsigned LocalIndex = LocalID >> Qualifiers::FastWidth;
+
+ if (LocalIndex < NUM_PREDEF_TYPE_IDS)
+ return LocalID;
+
+ ContinuousRangeMap<uint32_t, int, 2>::iterator I
+ = F.TypeRemap.find(LocalIndex - NUM_PREDEF_TYPE_IDS);
+ assert(I != F.TypeRemap.end() && "Invalid index into type index remap");
+
+ unsigned GlobalIndex = LocalIndex + I->second;
+ return (GlobalIndex << Qualifiers::FastWidth) | FastQuals;
+}
+
+unsigned ASTReader::getLocalTypeID(Module &M, serialization::TypeID GlobalID) {
+ unsigned FastQuals = GlobalID & Qualifiers::FastMask;
+ unsigned GlobalIndex = GlobalID >> Qualifiers::FastWidth;
+
+ if (GlobalIndex < NUM_PREDEF_TYPE_IDS)
+ return GlobalID;
+
+ GlobalIndex -= NUM_PREDEF_TYPE_IDS;
+ RecordLocation Loc = TypeCursorForIndex(GlobalIndex);
+
+ if (Loc.F == &M) {
+ // Simple case: the type ID came from the module we're asked to provide a
+ // type ID for. Shift the index appropriately;
+ unsigned LocalIndex
+ = GlobalIndex - M.GlobalBaseTypeIndex + M.LocalBaseTypeIndex
+ + NUM_PREDEF_TYPE_IDS ;
+ return (LocalIndex << Qualifiers::FastWidth) | FastQuals;
+ }
+
+ // Complex case: the type ID came from a module that M depends on, which may
+ // have had some remapping between the IDs used to store it in M and its
+ // location in the global space.
+ llvm::DenseMap<Module *, int>::iterator R = Loc.F->ReverseTypeRemap.find(&M);
+ if (R == Loc.F->ReverseTypeRemap.end())
+ return TypeID(-1); // FIXME: This is a terrible failure case
+
+ unsigned LocalIndex = GlobalIndex - Loc.F->GlobalBaseTypeIndex
+ + R->second + NUM_PREDEF_TYPE_IDS;
+ return (LocalIndex << Qualifiers::FastWidth) | FastQuals;
}
TypeID ASTReader::GetTypeID(QualType T) const {
return TypeIdx();
assert(!T.getLocalFastQualifiers());
+ // FIXME: Modules can't handle this. It's even dubious with chained PCH,
+ // because the same type (say, int*) can be serialized into different
+ // PCH files within the chain, and there's no way to know which of the
+ // ID numbers we actually want.
TypeIdxMap::const_iterator I = TypeIdxs.find(T);
// GetTypeIdx is mostly used for computing the hash of DeclarationNames and
// comparing keys of ASTDeclContextNameLookupTable.
DeclOffsets(0), BaseDeclID(0),
LocalNumCXXBaseSpecifiers(0), CXXBaseSpecifiersOffsets(0),
BaseCXXBaseSpecifiersID(0),
- LocalNumTypes(0), TypeOffsets(0), BaseTypeID(0), StatCache(0),
+ LocalNumTypes(0), TypeOffsets(0), GlobalBaseTypeIndex(0),
+ LocalBaseTypeIndex(0), StatCache(0),
NumPreallocatedPreprocessingEntities(0)
{}
llvm::errs() << " Base source location offset: " << SLocEntryBaseOffset
<< '\n';
dumpLocalRemap("Source location offset map", SLocRemap);
+ llvm::errs() << " Base type ID: " << GlobalBaseTypeIndex << '\n'
+ << " Number of types: " << LocalNumTypes << '\n';
+ dumpLocalRemap("Type ID map", TypeRemap);
}
Module *ModuleManager::lookup(StringRef Name) {
BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
Abbrev->Add(BitCodeAbbrevOp(TYPE_OFFSET));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // # of types
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // base type index
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // types block
unsigned TypeOffsetAbbrev = Stream.EmitAbbrev(Abbrev);
Record.clear();
Record.push_back(TYPE_OFFSET);
Record.push_back(TypeOffsets.size());
+ Record.push_back(FirstTypeID - NUM_PREDEF_TYPE_IDS);
Stream.EmitRecordWithBlob(TypeOffsetAbbrev, Record, data(TypeOffsets));
// Write the declaration offsets array
WriteStatCache(*StatCalls);
WriteSourceManagerBlock(Context.getSourceManager(), PP, isysroot);
- // Write the record of special types.
- Record.clear();
-
- AddTypeRef(Context.getBuiltinVaListType(), Record);
- AddTypeRef(Context.getObjCIdType(), Record);
- AddTypeRef(Context.getObjCSelType(), Record);
- AddTypeRef(Context.getObjCProtoType(), Record);
- AddTypeRef(Context.getObjCClassType(), Record);
- AddTypeRef(Context.getRawCFConstantStringType(), Record);
- AddTypeRef(Context.getRawObjCFastEnumerationStateType(), Record);
- AddTypeRef(Context.getFILEType(), Record);
- AddTypeRef(Context.getjmp_bufType(), Record);
- AddTypeRef(Context.getsigjmp_bufType(), Record);
- AddTypeRef(Context.ObjCIdRedefinitionType, Record);
- AddTypeRef(Context.ObjCClassRedefinitionType, Record);
- AddTypeRef(Context.getRawBlockdescriptorType(), Record);
- AddTypeRef(Context.getRawBlockdescriptorExtendedType(), Record);
- AddTypeRef(Context.ObjCSelRedefinitionType, Record);
- AddTypeRef(Context.getRawNSConstantStringType(), Record);
- Record.push_back(Context.isInt128Installed());
- AddTypeRef(Context.AutoDeductTy, Record);
- AddTypeRef(Context.AutoRRefDeductTy, Record);
- Stream.EmitRecord(SPECIAL_TYPES, Record);
+ // Form the record of special types.
+ RecordData SpecialTypes;
+ AddTypeRef(Context.getBuiltinVaListType(), SpecialTypes);
+ AddTypeRef(Context.getObjCIdType(), SpecialTypes);
+ AddTypeRef(Context.getObjCSelType(), SpecialTypes);
+ AddTypeRef(Context.getObjCProtoType(), SpecialTypes);
+ AddTypeRef(Context.getObjCClassType(), SpecialTypes);
+ AddTypeRef(Context.getRawCFConstantStringType(), SpecialTypes);
+ AddTypeRef(Context.getRawObjCFastEnumerationStateType(), SpecialTypes);
+ AddTypeRef(Context.getFILEType(), SpecialTypes);
+ AddTypeRef(Context.getjmp_bufType(), SpecialTypes);
+ AddTypeRef(Context.getsigjmp_bufType(), SpecialTypes);
+ AddTypeRef(Context.ObjCIdRedefinitionType, SpecialTypes);
+ AddTypeRef(Context.ObjCClassRedefinitionType, SpecialTypes);
+ AddTypeRef(Context.getRawBlockdescriptorType(), SpecialTypes);
+ AddTypeRef(Context.getRawBlockdescriptorExtendedType(), SpecialTypes);
+ AddTypeRef(Context.ObjCSelRedefinitionType, SpecialTypes);
+ AddTypeRef(Context.getRawNSConstantStringType(), SpecialTypes);
+ SpecialTypes.push_back(Context.isInt128Installed());
+ AddTypeRef(Context.AutoDeductTy, SpecialTypes);
+ AddTypeRef(Context.AutoRRefDeductTy, SpecialTypes);
// Keep writing types and declarations until all types and
// declarations have been written.
WriteCXXBaseSpecifiersOffsets();
+ Stream.EmitRecord(SPECIAL_TYPES, SpecialTypes);
+
// Write the record containing external, unnamed definitions.
if (!ExternalDefinitions.empty())
Stream.EmitRecord(EXTERNAL_DEFINITIONS, ExternalDefinitions);
io::Emit32(Out, (*M)->BaseSelectorID);
io::Emit32(Out, (*M)->BaseDeclID);
io::Emit32(Out, (*M)->BaseCXXBaseSpecifiersID);
- io::Emit32(Out, (*M)->BaseTypeID);
+ io::Emit32(Out, (*M)->GlobalBaseTypeIndex);
}
}
Record.clear();