32template <
typename MapT>
33static std::optional<MCRegister> lookupOptReg(
const MapT &Map,
34 typename MapT::key_type
Key) {
38 assert(It->second.isValid() &&
"invalid register stored in map");
62 if (CT->getTag() == dwarf::DW_TAG_array_type && CT->isVector())
67 if (DT && DT->getTag() == dwarf::DW_TAG_pointer_type)
72 NSDIFlagIsProtected = 1u << 0,
73 NSDIFlagIsPrivate = 1u << 1,
74 NSDIFlagIsPublic = NSDIFlagIsPrivate | NSDIFlagIsProtected,
75 NSDIFlagIsLocal = 1u << 2,
76 NSDIFlagIsDefinition = 1u << 3,
77 NSDIFlagFwdDecl = 1u << 4,
78 NSDIFlagArtificial = 1u << 5,
79 NSDIFlagExplicit = 1u << 6,
80 NSDIFlagPrototyped = 1u << 7,
81 NSDIFlagObjectPointer = 1u << 8,
82 NSDIFlagStaticMember = 1u << 9,
83 NSDIFlagIndirectVariable = 1u << 10,
84 NSDIFlagLValueReference = 1u << 11,
85 NSDIFlagRValueReference = 1u << 12,
86 NSDIFlagIsOptimized = 1u << 13,
87 NSDIFlagIsEnumClass = 1u << 14,
88 NSDIFlagTypePassByValue = 1u << 15,
89 NSDIFlagTypePassByReference = 1u << 16,
90 NSDIFlagUnknownPhysicalLayout = 1u << 17,
96 Flags |= NSDIFlagIsPublic;
98 Flags |= NSDIFlagIsProtected;
100 Flags |= NSDIFlagIsPrivate;
101 if (DFlags & DINode::FlagFwdDecl)
102 Flags |= NSDIFlagFwdDecl;
103 if (DFlags & DINode::FlagArtificial)
104 Flags |= NSDIFlagArtificial;
105 if (DFlags & DINode::FlagExplicit)
106 Flags |= NSDIFlagExplicit;
107 if (DFlags & DINode::FlagPrototyped)
108 Flags |= NSDIFlagPrototyped;
109 if (DFlags & DINode::FlagObjectPointer)
110 Flags |= NSDIFlagObjectPointer;
111 if (DFlags & DINode::FlagStaticMember)
112 Flags |= NSDIFlagStaticMember;
113 if (DFlags & DINode::FlagLValueReference)
114 Flags |= NSDIFlagLValueReference;
115 if (DFlags & DINode::FlagRValueReference)
116 Flags |= NSDIFlagRValueReference;
117 if (DFlags & DINode::FlagTypePassByValue)
118 Flags |= NSDIFlagTypePassByValue;
119 if (DFlags & DINode::FlagTypePassByReference)
120 Flags |= NSDIFlagTypePassByReference;
121 if (DFlags & DINode::FlagEnumClass)
122 Flags |= NSDIFlagIsEnumClass;
129 if (GV->isLocalToUnit())
130 Flags |= NSDIFlagIsLocal;
131 if (GV->isDefinition())
132 Flags |= NSDIFlagIsDefinition;
135 if (SP->isLocalToUnit())
136 Flags |= NSDIFlagIsLocal;
137 if (SP->isOptimized())
138 Flags |= NSDIFlagIsOptimized;
139 if (SP->isDefinition())
140 Flags |= NSDIFlagIsDefinition;
141 Flags |= mapDIFlagsToNonSemantic(SP->getFlags());
143 if (DN->
getTag() == dwarf::DW_TAG_reference_type)
144 Flags |= NSDIFlagLValueReference;
145 if (DN->
getTag() == dwarf::DW_TAG_rvalue_reference_type)
146 Flags |= NSDIFlagRValueReference;
148 Flags |= mapDIFlagsToNonSemantic(Ty->getFlags());
150 Flags |= mapDIFlagsToNonSemantic(LV->getFlags());
162unsigned SPIRVNonSemanticDebugHandler::toNSDISrcLang(
unsigned DwarfSrcLang) {
163 switch (DwarfSrcLang) {
164 case dwarf::DW_LANG_OpenCL:
166 case dwarf::DW_LANG_OpenCL_CPP:
168 case dwarf::DW_LANG_CPP_for_OpenCL:
170 case dwarf::DW_LANG_GLSL:
172 case dwarf::DW_LANG_HLSL:
174 case dwarf::DW_LANG_SYCL:
176 case dwarf::DW_LANG_Zig:
191 CompileUnits.clear();
193 PointerTypes.clear();
194 SubroutineTypes.clear();
196 SubprogramDeclarations.clear();
197 DebugFunctionDeclarationRegs.clear();
198 ScopeToPathOpStringReg.clear();
199 CUToCompilationUnitDbgReg.clear();
200 DebugSourceRegByFileStr.clear();
201 DebugTypeRegs.clear();
202 OpStringContentCache.clear();
203 I32ConstantCache.clear();
204 DebugTypeFunctionCache.clear();
205 GlobalDIEmitted =
false;
207 NonSemanticOpStringsSectionEmitted =
false;
216 CompileUnitInfo Info;
219 Info.FilePath = File->getFilename();
222 File->getFilename());
225 Info.SpirvSourceLanguage = toNSDISrcLang(
CU->getSourceLanguage().getName());
226 CompileUnits.push_back(std::move(Info));
232 if (
const NamedMDNode *Flags = M->getNamedMetadata(
"llvm.module.flags")) {
233 for (
const auto *
Op : Flags->operands()) {
247 partitionTypes(Ty, BasicTypes, PointerTypes, SubroutineTypes, VectorTypes);
251 if (!SP->isDefinition())
252 SubprogramDeclarations.push_back(SP);
258 if (CompileUnits.empty())
260 if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_non_semantic_info))
269 constexpr unsigned NSSet =
static_cast<unsigned>(
270 SPIRV::InstructionSet::NonSemantic_Shader_DebugInfo_100);
275void SPIRVNonSemanticDebugHandler::emitMCInst(
MCInst &Inst) {
280SPIRVNonSemanticDebugHandler::emitOpString(
StringRef S,
291MCRegister SPIRVNonSemanticDebugHandler::emitOpStringIfNew(
294 assert(!NonSemanticOpStringsSectionEmitted &&
295 "emitOpStringIfNew is only valid while emitting SPIR-V section 7");
297 auto [It,
Inserted] = OpStringContentCache.try_emplace(S, MCRegister());
299 It->second = emitOpString(S, MAI);
306 assert(NonSemanticOpStringsSectionEmitted &&
307 "getCachedOpStringReg requires emitNonSemanticDebugStrings() first");
309 auto It = OpStringContentCache.find(S);
310 assert(It != OpStringContentCache.end() &&
311 "NSDI OpString missing from cache; emitNonSemanticDebugStrings must "
312 "cache every string used in section 10");
316MCRegister SPIRVNonSemanticDebugHandler::emitOpConstantI32(
333MCRegister SPIRVNonSemanticDebugHandler::emitExtInst(
334 SPIRV::NonSemanticExtInst::NonSemanticExtInst Opcode,
344 for (MCRegister R : Operands)
350MCRegister SPIRVNonSemanticDebugHandler::getOrEmitDebugTypeFunction(
358 MCRegister
Reg = emitExtInst(SPIRV::NonSemanticExtInst::DebugTypeFunction,
359 VoidTypeReg, ExtInstSetReg,
Ops, MAI);
364MCRegister SPIRVNonSemanticDebugHandler::getOrEmitOpTypeVoidReg(
366 if (!CachedOpTypeVoidReg.isValid())
367 CachedOpTypeVoidReg = findOrEmitOpTypeVoid(MAI);
368 return CachedOpTypeVoidReg;
371MCRegister SPIRVNonSemanticDebugHandler::getOrEmitOpTypeInt32Reg(
373 if (!CachedOpTypeInt32Reg.isValid())
374 CachedOpTypeInt32Reg = findOrEmitOpTypeInt32(MAI);
375 return CachedOpTypeInt32Reg;
378MCRegister SPIRVNonSemanticDebugHandler::findOrEmitOpTypeVoid(
381 if (
MI->getOpcode() == SPIRV::OpTypeVoid)
392MCRegister SPIRVNonSemanticDebugHandler::findOrEmitOpTypeInt32(
395 if (
MI->getOpcode() == SPIRV::OpTypeInt &&
396 MI->getOperand(1).getImm() == 32 &&
MI->getOperand(2).getImm() == 0)
409std::optional<MCRegister> SPIRVNonSemanticDebugHandler::emitDebugTypePointer(
414 if (!PT->getDWARFAddressSpace().has_value())
417 MCRegister VoidTypeReg = getOrEmitOpTypeVoidReg(MAI);
418 MCRegister I32TypeReg = getOrEmitOpTypeInt32Reg(MAI);
419 MCRegister DebugTypePointerFlagsReg =
420 emitOpConstantI32(transDebugFlags(PT), I32TypeReg, MAI);
424 const auto &
ST =
static_cast<const SPIRVSubtarget &
>(
Asm->getSubtargetInfo());
425 MCRegister StorageClassReg = emitOpConstantI32(
429 if (
const DIType *BaseTy = PT->getBaseType()) {
430 auto BaseIt = DebugTypeRegs.find(BaseTy);
431 if (BaseIt != DebugTypeRegs.end())
433 SPIRV::NonSemanticExtInst::DebugTypePointer, VoidTypeReg,
435 {BaseIt->second, StorageClassReg, DebugTypePointerFlagsReg}, MAI);
444 SPIRV::NonSemanticExtInst::DebugTypePointer, VoidTypeReg, ExtInstSetReg,
445 {CachedDebugInfoNoneReg, StorageClassReg, DebugTypePointerFlagsReg}, MAI);
448std::optional<MCRegister>
449SPIRVNonSemanticDebugHandler::emitDebugTypeFunctionForSubroutineType(
452 MCRegister VoidTypeReg = getOrEmitOpTypeVoidReg(MAI);
453 MCRegister I32TypeReg = getOrEmitOpTypeInt32Reg(MAI);
454 MCRegister DebugTypeFunctionFlagsReg =
455 emitOpConstantI32(transDebugFlags(ST), I32TypeReg, MAI);
456 DITypeArray
TA =
ST->getTypeArray();
458 Ops.push_back(DebugTypeFunctionFlagsReg);
463 Ops.push_back(VoidTypeReg);
465 for (
unsigned I = 0,
E =
TA.size();
I !=
E; ++
I) {
466 bool IsReturnType = (
I == 0);
467 auto OptReg = mapDISignatureTypeToReg(TA[
I], VoidTypeReg, IsReturnType);
472 Ops.push_back(*OptReg);
475 return getOrEmitDebugTypeFunction(
Ops, VoidTypeReg, ExtInstSetReg, MAI);
479std::optional<MCRegister>
480SPIRVNonSemanticDebugHandler::resolveDebugFunctionDeclarationParent(
482 const DIScope *
Scope =
SP->getScope();
489 return lookupOptReg(DebugTypeRegs, Ty);
492 const DICompileUnit *ParentCU =
SP->getUnit();
493 if (!ParentCU && !CompileUnits.empty())
494 ParentCU = CompileUnits[0].TheCU;
497 return lookupOptReg(CUToCompilationUnitDbgReg, ParentCU);
500std::optional<MCRegister>
501SPIRVNonSemanticDebugHandler::emitDebugFunctionDeclaration(
504 assert(SP &&
"SP must not be null in emitDebugFunctionDeclaration");
506 "SP must not be a definition in emitDebugFunctionDeclaration");
509 const DISubroutineType *
ST =
SP->getType();
511 auto FnTyRegOpt = lookupOptReg(DebugTypeRegs, ST);
514 MCRegister FnTyReg = *FnTyRegOpt;
516 auto ParentRegOpt = resolveDebugFunctionDeclarationParent(SP);
520 MCRegister ParentReg = *ParentRegOpt;
522 auto PathStrIt = ScopeToPathOpStringReg.find(SP);
523 assert(PathStrIt != ScopeToPathOpStringReg.end() &&
524 "declaration path OpString must be cached in "
525 "emitNonSemanticDebugStrings");
526 MCRegister FileStrReg = PathStrIt->second;
528 "declaration path OpString id must be valid once cached");
530 MCRegister NameReg = getCachedOpStringReg(
SP->getName());
531 MCRegister LinkageReg = getCachedOpStringReg(
SP->getLinkageName());
532 MCRegister SrcReg = getOrEmitDebugSourceForFileStrReg(FileStrReg, VoidTypeReg,
536 emitOpConstantI32(
static_cast<uint32_t
>(
SP->getLine()), I32TypeReg, MAI);
537 MCRegister ColReg = emitOpConstantI32(0, I32TypeReg, MAI);
539 uint32_t FlagsVal = transDebugFlags(SP);
542 FlagsVal &= ~NSDIFlagIsDefinition;
543 MCRegister FlagsReg = emitOpConstantI32(FlagsVal, I32TypeReg, MAI);
545 return emitExtInst(SPIRV::NonSemanticExtInst::DebugFunctionDeclaration,
546 VoidTypeReg, ExtInstSetReg,
547 {NameReg, FnTyReg, SrcReg, LineReg, ColReg, ParentReg,
548 LinkageReg, FlagsReg},
552std::optional<MCRegister> SPIRVNonSemanticDebugHandler::mapDISignatureTypeToReg(
557 assert(CachedDebugInfoNoneReg.isValid() &&
558 "DebugInfoNone must be emitted before DISubroutineType operands");
559 return CachedDebugInfoNoneReg;
561 return lookupOptReg(DebugTypeRegs, Ty);
564std::optional<MCRegister> SPIRVNonSemanticDebugHandler::emitDebugTypeVector(
570 auto BTIt = DebugTypeRegs.find(BaseTy);
571 if (BTIt == DebugTypeRegs.end())
584 MCRegister VoidTypeReg = getOrEmitOpTypeVoidReg(MAI);
585 MCRegister I32TypeReg = getOrEmitOpTypeInt32Reg(MAI);
586 MCRegister CountReg = emitOpConstantI32(
587 static_cast<uint32_t
>(CI->getZExtValue()), I32TypeReg, MAI);
588 return emitExtInst(SPIRV::NonSemanticExtInst::DebugTypeVector, VoidTypeReg,
589 ExtInstSetReg, {BTIt->second, CountReg}, MAI);
594 if (CompileUnits.empty())
599 constexpr unsigned NSSet =
static_cast<unsigned>(
600 SPIRV::InstructionSet::NonSemantic_Shader_DebugInfo_100);
604 for (
const CompileUnitInfo &Info : CompileUnits) {
606 MCRegister PathReg = emitOpStringIfNew(Info.FilePath, MAI);
607 ScopeToPathOpStringReg[Info.TheCU] = PathReg;
608 if (
const DIFile *
F = Info.TheCU->getFile())
609 ScopeToPathOpStringReg[
F] = PathReg;
614 emitOpStringIfNew(
BT->getName(), MAI);
617 emitOpStringIfNew(SP->getName(), MAI);
618 emitOpStringIfNew(SP->getLinkageName(), MAI);
619 ScopeToPathOpStringReg[SP] = emitOpStringIfNew(getDebugFullPath(SP), MAI);
623 NonSemanticOpStringsSectionEmitted =
true;
629 if (GlobalDIEmitted || CompileUnits.empty())
631 GlobalDIEmitted =
true;
634 constexpr unsigned NSSet =
static_cast<unsigned>(
635 SPIRV::InstructionSet::NonSemantic_Shader_DebugInfo_100);
641 assert(NonSemanticOpStringsSectionEmitted &&
642 "emitNonSemanticDebugStrings() must run before "
643 "emitNonSemanticGlobalDebugInfo()");
646 MCRegister VoidTypeReg = getOrEmitOpTypeVoidReg(MAI);
647 MCRegister I32TypeReg = getOrEmitOpTypeInt32Reg(MAI);
649 CachedDebugInfoNoneReg = emitExtInst(SPIRV::NonSemanticExtInst::DebugInfoNone,
650 VoidTypeReg, ExtInstSetReg, {}, MAI);
662 MCRegister DebugInfoVersionReg = emitOpConstantI32(100, I32TypeReg, MAI);
664 emitOpConstantI32(
static_cast<uint32_t>(DwarfVersion), I32TypeReg, MAI);
669 map_to_vector(CompileUnits, [&](
const CompileUnitInfo &Info) {
670 return emitOpConstantI32(Info.SpirvSourceLanguage, I32TypeReg, MAI);
674 for (
auto [Info, SrcLangReg] :
llvm::zip(CompileUnits, SrcLangRegs)) {
675 MCRegister FileStrReg = ScopeToPathOpStringReg.lookup(Info.TheCU);
677 "CU path OpString must be emitted in emitNonSemanticDebugStrings");
678 MCRegister DebugSourceReg = getOrEmitDebugSourceForFileStrReg(
679 FileStrReg, VoidTypeReg, ExtInstSetReg, MAI);
681 SPIRV::NonSemanticExtInst::DebugCompilationUnit, VoidTypeReg,
683 {DebugInfoVersionReg, DwarfVersionReg, DebugSourceReg, SrcLangReg},
686 CUToCompilationUnitDbgReg[Info.TheCU] = CUDbgReg;
691 MCRegister I32ZeroReg = emitOpConstantI32(0, I32TypeReg, MAI);
693 DebugTypeRegs.clear();
696 MCRegister NameReg = getCachedOpStringReg(
BT->getName());
698 static_cast<uint32_t>(
BT->getSizeInBits()), I32TypeReg, MAI);
702 unsigned Encoding = 0;
703 switch (
BT->getEncoding()) {
704 case dwarf::DW_ATE_address:
707 case dwarf::DW_ATE_boolean:
710 case dwarf::DW_ATE_float:
713 case dwarf::DW_ATE_signed:
716 case dwarf::DW_ATE_signed_char:
719 case dwarf::DW_ATE_unsigned:
722 case dwarf::DW_ATE_unsigned_char:
726 MCRegister EncodingReg = emitOpConstantI32(Encoding, I32TypeReg, MAI);
729 SPIRV::NonSemanticExtInst::DebugTypeBasic, VoidTypeReg, ExtInstSetReg,
730 {NameReg, SizeReg, EncodingReg, I32ZeroReg}, MAI);
731 DebugTypeRegs[
BT] = BTReg;
736 if (
auto VecReg = emitDebugTypeVector(VT, ExtInstSetReg, MAI))
737 DebugTypeRegs[VT] = *VecReg;
742 if (
auto PtrReg = emitDebugTypePointer(PT, ExtInstSetReg, MAI))
743 DebugTypeRegs[PT] = *PtrReg;
749 emitDebugTypeFunctionForSubroutineType(ST, ExtInstSetReg, MAI))
750 DebugTypeRegs[ST] = *FnTyReg;
755 if (
auto DeclReg = emitDebugFunctionDeclaration(SP, VoidTypeReg, I32TypeReg,
757 DebugFunctionDeclarationRegs[SP] = *DeclReg;
762SPIRVNonSemanticDebugHandler::getDebugFullPath(
const DIScope *Scope)
const {
778MCRegister SPIRVNonSemanticDebugHandler::getOrEmitDebugSourceForFileStrReg(
781 const unsigned Key = FileStrReg.
id();
782 auto It = DebugSourceRegByFileStr.find(
Key);
783 if (It != DebugSourceRegByFileStr.end())
786 MCRegister
DS = emitExtInst(SPIRV::NonSemanticExtInst::DebugSource,
787 VoidTypeReg, ExtInstSetReg, {FileStrReg}, MAI);
788 DebugSourceRegByFileStr[
Key] =
DS;
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
This file contains constants used for implementing Dwarf debug support.
Module.h This file contains the declarations for the Module class.
const AbstractManglingParser< Derived, Alloc >::OperatorInfo AbstractManglingParser< Derived, Alloc >::Ops[]
static constexpr StringLiteral Filename
Represent a constant reference to an array (0 or more elements consecutively in memory),...
This class is intended to be used as a driving class for all asm writers.
std::unique_ptr< MCStreamer > OutStreamer
This is the MCStreamer object for the file we are generating.
const MCSubtargetInfo & getSubtargetInfo() const
Return information about subtarget.
Basic type, like 'int' or 'float'.
DINodeArray getElements() const
DIType * getBaseType() const
Tagged DWARF-like metadata node.
LLVM_ABI dwarf::Tag getTag() const
Base class for scope-like contexts.
Subprogram description. Uses SubclassData1.
Type array for a subprogram.
AsmPrinter * Asm
Target of debug info emission.
DebugHandlerBase(AsmPrinter *A)
void beginModule(Module *M) override
Utility to find all debug info in a module.
LLVM_ABI void processModule(const Module &M)
Process entire module and collect debug info anchors.
iterator_range< subprogram_iterator > subprograms() const
iterator_range< type_iterator > types() const
Instances of this class represent a single low-level machine instruction.
void addOperand(const MCOperand Op)
void setOpcode(unsigned Op)
static MCOperand createReg(MCRegister Reg)
static MCOperand createImm(int64_t Val)
Wrapper class representing physical registers. Should be passed by value.
constexpr bool isValid() const
constexpr unsigned id() const
Tracking metadata reference owned by Metadata.
bool equalsStr(StringRef Str) const
A Module instance is used to store all the information related to an LLVM module.
void emitNonSemanticDebugStrings(SPIRV::ModuleAnalysisInfo &MAI)
Emit OpString instructions for all NSDI file paths and basic type names into the debug section (secti...
void beginModule(Module *M) override
Collect compile-unit metadata from the module.
void emitNonSemanticGlobalDebugInfo(SPIRV::ModuleAnalysisInfo &MAI)
Emit module-scope NSDI instructions (DebugSource, DebugCompilationUnit, DebugTypeBasic,...
void prepareModuleOutput(const SPIRVSubtarget &ST, SPIRV::ModuleAnalysisInfo &MAI)
Add SPV_KHR_non_semantic_info extension and NonSemantic.Shader.DebugInfo.100 ext inst set entry to MA...
SPIRVNonSemanticDebugHandler(AsmPrinter &AP)
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
void assign(StringRef RHS)
Assign from a StringRef.
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Represent a constant reference to a string, i.e.
LLVM Value Representation.
Scope
Defines the scope in which this symbol should be visible: Default – Visible in the public interface o...
LLVM_ABI bool is_absolute(const Twine &path, Style style=Style::native)
Is path absolute?
LLVM_ABI void append(SmallVectorImpl< char > &path, const Twine &a, const Twine &b="", const Twine &c="", const Twine &d="")
Append to path.
This is an optimization pass for GlobalISel generic memory operations.
detail::zippy< detail::zip_shortest, T, U, Args... > zip(T &&t, U &&u, Args &&...args)
zip iterator for two or more iteratable types.
UnaryFunction for_each(R &&Range, UnaryFunction F)
Provide wrappers to std::for_each which take ranges instead of having to pass begin/end explicitly.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
auto map_to_vector(ContainerTy &&C, FuncTy &&F)
Map a range to a SmallVector with element types deduced from the mapping.
auto dyn_cast_if_present(const Y &Val)
dyn_cast_if_present<X> - Functionally identical to dyn_cast, except that a null (or none in the case ...
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
auto dyn_cast_or_null(const Y &Val)
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
LLVM_ATTRIBUTE_VISIBILITY_DEFAULT AnalysisKey InnerAnalysisManagerProxy< AnalysisManagerT, IRUnitT, ExtraArgTs... >::Key
SPIRV::StorageClass::StorageClass addressSpaceToStorageClass(unsigned AddrSpace, const SPIRVSubtarget &STI)
DWARFExpression::Operation Op
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
void addStringImm(const StringRef &Str, MCInst &Inst)
MCRegister getExtInstSetReg(unsigned SetNum)
DenseMap< unsigned, MCRegister > ExtInstSetMap
InstrList & getMSInstrs(unsigned MSType)
MCRegister getRegisterAlias(const MachineFunction *MF, Register Reg)
MCRegister getNextIDRegister()
void addExtension(Extension::Extension ToAdd)