SPIR-V NonSemantic AuxData Instructions ======================================= Version 1.00 Contact ------- To report problems with this extension, please open a new issue at: https://github.com/KhronosGroup/SPIRV-LLVM-Translator Contributors ------------ - Nick Sarnie, Intel - Dmitry Sidorov, AMD Notice ------ Copyright (c) 2026 The Khronos Group Inc. Copyright terms at http://www.khronos.org/registry/speccopyright.html Status ------ - Complete draft. Defined and consumed by the SPIRV-LLVM-Translator; not formally ratified by the SPIR-V Working Group. Version ------- [width="40%",cols="25,25"] |======================================== | Last Modified Date | 2026-05-05 | Revision | 2 |======================================== Dependencies ------------ This extension is written against the SPIR-V Specification, Version 1.6 Revision 7. This instruction set requires either SPIR-V 1.6 or *SPV_KHR_non_semantic_info* extension. Overview -------- The *NonSemantic.AuxData* extended instruction set encodes auxiliary data attached to LLVM IR `Function` and `GlobalVariable` objects specifically, LLVM *attributes* and LLVM *metadata*, so that this information can survive a round trip through SPIR-V and be restored on reverse translation. The information described by these instructions is, by construction, *non-semantic*: a SPIR-V consumer that does not understand or does not care about LLVM-level annotations may safely strip every instruction in this set without changing the meaning of the module. The set exists purely to act as a transparent transport for tooling that needs to preserve LLVM metadata (for example, frontend or middle-end contracts expressed via attribute/metadata strings) across a SPIR-V boundary. Import this extended instruction set using an `OpExtInstImport` "NonSemantic.AuxData" instruction. Terminology ----------- The terms below are used as defined in the LLVM Language Reference Manual (https://llvm.org/docs/LangRef.html): - *Function attribute* / *Global variable attribute* - an attribute attached to an LLVM `Function` or `GlobalVariable`. May be either an enum-kind attribute (e.g. `nounwind`, `readonly`) or a string attribute, with or without a string value; - *Function metadata* / *global variable metadata* - a named LLVM `MDNode` attached to a `Function` or `GlobalVariable`. The node's operands are an ordered list, each of which is either an `MDString` or a `ValueAsMetadata` wrapping a constant. - *Linkage type* - the linkage classification of an LLVM `GlobalValue`, as enumerated by `llvm::GlobalValue::LinkageTypes` and described in the "Linkage Types" section of the LLVM Language Reference Manual. The phrase "global object" refers collectively to either an LLVM `Function` or an LLVM `GlobalVariable`. 1. Binary Form -------------- All instructions in this set: - have a 'Result Type' that must be *OpTypeVoid*; - produce a 'Result ' that is not consumed by any other instruction; - have no associated capability and require no capability beyond what is required to use `OpExtInst` against a non-semantic extended instruction set; - may appear at module scope, after all type, constant, and global declarations they reference have been declared, in the locations permitted for non-semantic instructions by *SPV_KHR_non_semantic_info*. A producer should emit all *NonSemantic.AuxData* instructions in the section of the module reserved for debug / non-semantic instructions and must emit every operand 'OpString' and operand 'OpConstant' before the *NonSemantic.AuxData* instruction that uses it. A producer must not use this set to encode information that is already representable through, and is in fact represented through, another SPIR-V mechanism. In particular, the SPIRV-LLVM-Translator deliberately does *not* emit *NonSemantic.AuxData* instructions for: - LLVM metadata named `spirv.Decorations` and `spirv.ParameterDecorations` (these are already lowered to native *OpDecorate* / *OpMemberDecorate* chains); - LLVM debug-info metadata (the `!dbg` attachment, kind `LLVMContext::MD_dbg`), which is encoded via `OpLine`, *NonSemantic.Shader.DebugInfo.100* / *OpenCL.DebugInfo.100*, or similar facilities. A consumer must tolerate the absence of any individual *NonSemantic.AuxData* instruction; the set has no internal ordering or dependency requirements between its own instructions. Enumeration ~~~~~~~~~~~ The following table lists the instruction numbers assigned by this extended instruction set: [width="60%"] |======================================== | Instruction number | Instruction name | 0 | <> | 1 | <> | 2 | <> | 3 | <> | 4 | <> |======================================== [[LinkageType]] Linkage Type ^^^^^^^^^^^^ The 'Linkage Type' operand of the <> instruction is the '' of a 32-bit integer *OpConstant* whose value is one of the entries in the table below. The set of recognized values may grow in future revisions of this specification; values not listed here are reserved. A consumer that does not recognize a 'Linkage Type' value must ignore the enclosing instruction. [width="80%",cols="1,3,4"] |======================================== | Value | Name | Meaning | 0 | *AvailableExternally* | The target has LLVM `available_externally` linkage. The definition is provided for the consumer's benefit (for example, to enable inlining) but is not emitted as a separate symbol; consumers that lower the SPIR-V module back to LLVM IR should set this linkage on the corresponding `GlobalValue` after reverse translation, and should not consider the definition to participate in linking. |======================================== Instructions ~~~~~~~~~~~~ [cols="2*1,3*2,1,3,3,3"] |====== 9+a|[[NonSemanticAuxDataFunctionAttribute]]*NonSemanticAuxDataFunctionAttribute* + + Record one LLVM-IR function attribute attached to an `OpFunction`. + + 'Result Type' must be *OpTypeVoid*. + + 'Target' is the '' of the *OpFunction* the attribute is attached to. + + 'Attribute Name' is the '' of an *OpString*. For LLVM string-kind attributes (`AttributeImpl::isStringAttribute()` is true) it contains the attribute key exactly as it appears in the LLVM module (for example `"sycl-unique-id"`, `"foo"`). For LLVM enum-kind attributes (for example `nounwind`, `readonly`) it contains the attribute spelling as produced by `llvm::Attribute::getNameFromAttrKind` (for example `"nounwind"`). + + 'Attribute Value' is the '' of an *OpString* holding the string value associated with a string-kind attribute (for example `"32"` in `"sycl-device-global-size"="32"`). 'Attribute Value' must be omitted when the source attribute has no value (for example `"foo"` or any enum-kind attribute), and must be present otherwise. + + For an LLVM attribute that is neither a string-kind attribute nor a plain enum-kind attribute (for example a typed or integer attribute that has no compact textual key/value form), the producer shall emit 'Attribute Name' as the '' of an *OpString* containing the full textual rendering returned by `llvm::Attribute::getAsString()`, and shall omit 'Attribute Value'. A consumer encountering such a form should treat the entire string as an opaque attribute spelling. | 7 or 8 | 12 | '' + 'Result Type' | 'Result ' | ' Set' | 1 | '' 'Target' | '' 'Attribute Name' | Optional + '' 'Attribute Value' |====== [cols="2*1,3*2,1,3,3,3"] |====== 9+a|[[NonSemanticAuxDataGlobalVariableAttribute]]*NonSemanticAuxDataGlobalVariableAttribute* + + Record one LLVM-IR attribute attached to a global variable. + + 'Result Type' must be *OpTypeVoid*. + + 'Target' is the '' of the *OpVariable* (declared at module scope) the attribute is attached to. + + 'Attribute Name' and 'Attribute Value' have the same form, the same encoding rules, and the same optionality rules as the corresponding operands of <>. | 7 or 8 | 12 | '' + 'Result Type' | 'Result ' | ' Set' | 3 | '' 'Target' | '' 'Attribute Name' | Optional + '' 'Attribute Value' |====== [cols="2*1,3*2,1,3,3,3"] |====== 9+a|[[NonSemanticAuxDataFunctionMetadata]]*NonSemanticAuxDataFunctionMetadata* + + Record one named LLVM-IR metadata attachment on an `OpFunction`. + + 'Result Type' must be *OpTypeVoid*. + + 'Target' is the '' of the *OpFunction* the metadata is attached to. + + 'Metadata Name' is the '' of an *OpString* containing the metadata kind name, exactly as it appears in the LLVM module (for example `"foo"`, `"absolute_symbol"`, `"prof"`). + + 'Metadata Value' operands form a variable-length, ordered list mirroring the operand list of the source `MDNode`. Each operand shall be one of: + + - the '' of an *OpString*, encoding an `MDString` operand whose value is that string; or + - the '' of any other SPIR-V value (typically an *OpConstant* or *OpConstantComposite*), encoding a `ValueAsMetadata` operand wrapping the corresponding LLVM constant. The translation between the SPIR-V value and the LLVM constant follows the normal forward / reverse rules of the surrounding SPIR-V value translation. + + The number of 'Metadata Value' operands MAY be zero (for an empty `MDNode`). It is unbounded otherwise. A consumer must skip a *NonSemanticAuxDataFunctionMetadata* instruction whose 'Metadata Name' is already attached to 'Target' through some other reverse-translation path, to avoid creating duplicate metadata attachments. | 7 + 'variable' | 12 | '' + 'Result Type' | 'Result ' | ' Set' | 0 | '' 'Target' | '' 'Metadata Name' | 'Metadata Value', 'Metadata Value', ... (zero or more) |====== [cols="2*1,3*2,1,3,3,3"] |====== 9+a|[[NonSemanticAuxDataGlobalVariableMetadata]]*NonSemanticAuxDataGlobalVariableMetadata* + + Record one named LLVM-IR metadata attachment on a global variable. + + 'Result Type' must be *OpTypeVoid*. + + 'Target' is the '' of the *OpVariable* (declared at module scope) the metadata is attached to. + + 'Metadata Name' and 'Metadata Value' operands have the same form, the same encoding rules, the same exclusions, and the same duplicate-skip recommendation as the corresponding operands of <>. | 7 + 'variable' | 12 | '' + 'Result Type' | 'Result ' | ' Set' | 2 | '' 'Target' | '' 'Metadata Name' | 'Metadata Value', 'Metadata Value', ... (zero or more) |====== [cols="2*1,3*2,1,3,3"] |====== 8+a|[[NonSemanticAuxDataLinkage]]*NonSemanticAuxDataLinkage* + + Record the LLVM-IR linkage type of a global object. + + 'Result Type' must be *OpTypeVoid*. + + 'Target' is the '' of the *OpFunction* or of the module-scope *OpVariable* whose linkage is being recorded. Linkage is a property of the LLVM `GlobalValue` base class, so the same instruction is used regardless of which kind of global object 'Target' refers to. + + At most one *NonSemanticAuxDataLinkage* instruction should reference any given 'Target'; if a producer emits more than one, a consumer must honor only the last one in module order. + + 'Linkage Type' is the '' of a 32-bit integer *OpConstant* whose value is taken from the <> table. + + A producer must not emit this instruction for the default LLVM linkage (`external`); the absence of a *NonSemanticAuxDataLinkage* record on a global object means the object carries the linkage that the SPIR-V module otherwise implies. A consumer that sees a 'Linkage Type' value it does not recognize must silently ignore the instruction. | 7 | 12 | '' + 'Result Type' | 'Result ' | ' Set' | 4 | '' 'Target' | '' 'Linkage Type' |====== 2. Encoding Notes ----------------- This section is informative; it is not part of the normative content of the specification. Round-trip behaviour ~~~~~~~~~~~~~~~~~~~~ The set is designed to be lossless on a producer/consumer pair that both opt in to its use. For each global object the SPIRV-LLVM-Translator walks `Function::getAttributes().getFnAttrs()` (or `GlobalVariable::getAttributes()`) once and emits one `...Attribute` instruction per attribute, then walks `GlobalObject::getAllMetadata()` once and emits one `...Metadata` instruction per metadata attachment, in the order the LLVM data structures yield them. The reverse path performs the inverse operation, calling the LLVM API that adds an attribute or sets a metadata kind on the corresponding global object. The specification sets no restrictions regarding how much `NonSemanticAuxData` instructions can annotate a single 'Target' nor it forbids a case of duplicated information being attached to the 'Target'. It is SPIR-V consumer duty to ensure LLVM module validity after the round-trip. Interaction with attribute-kind translation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Some LLVM enum-kind attributes are also produced as a side effect of unrelated reverse translation (for example, `nounwind` is set on intrinsic-like callees regardless of *NonSemantic.AuxData*). When the reverse translator processes a `...Attribute` instruction whose 'Attribute Name' resolves to an `Attribute::AttrKind` already present on the target, it must skip the instruction so as not to duplicate the attribute. The same skip rule applies for string-kind attributes already present on the target. Issues ------ None. Revision History ---------------- [cols="5,15,15,70"] [grid="rows"] [options="header"] |======================================== |Rev|Date|Author|Changes |1|xxxx-xx-xx|Nick Sarnie|Initial draft |2|2026-05-05|Dmitry Sidorov|Finalize spec, add available_externally |========================================