LLVM 24.0.0git
SPIRVAuxDataHandler.cpp
Go to the documentation of this file.
1//===-- SPIRVAuxDataHandler.cpp - NonSemantic.AuxData emitter -*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
11#include "SPIRVSubtarget.h"
12#include "SPIRVUtils.h"
14#include "llvm/IR/Attributes.h"
15#include "llvm/IR/Constants.h"
16#include "llvm/IR/Function.h"
19#include "llvm/IR/LLVMContext.h"
20#include "llvm/IR/Metadata.h"
21#include "llvm/IR/Module.h"
22#include "llvm/MC/MCInst.h"
23#include "llvm/MC/MCStreamer.h"
27
28using namespace llvm;
29
31 "spirv-preserve-auxdata",
32 cl::desc("Preserve LLVM attributes and metadata as "
33 "NonSemantic.AuxData ExtInst annotations (requires "
34 "SPV_KHR_non_semantic_info)"),
35 cl::Hidden, cl::init(false));
36
37namespace {
38enum AuxDataLinkageType : uint32_t {
39 AvailableExternally = 0,
40};
41
42constexpr unsigned NonSemanticAuxDataSet =
43 static_cast<unsigned>(SPIRV::InstructionSet::NonSemantic_AuxData);
44
45AttributeSet getGOAttrs(const GlobalObject *GO) {
46 if (const auto *F = dyn_cast<Function>(GO))
47 return F->getAttributes().getFnAttrs();
48 return cast<GlobalVariable>(GO)->getAttributes();
49}
50} // namespace
51
52static bool wasAvailableExternally(const GlobalObject *GO) {
53 if (const auto *F = dyn_cast<Function>(GO))
54 return F->hasFnAttribute(SPIRV_WAS_AVAILABLE_EXTERNALLY_ATTR);
55 return cast<GlobalVariable>(GO)->getAttributes().hasAttribute(
57}
58
59// Return true if any function definition may get an AuxData record.
60static bool hasFunctionAuxData(const Module &M) {
61 return any_of(M.functions(), [](const Function &F) {
62 return !F.isDeclaration() &&
63 (F.getAttributes().hasFnAttrs() || F.hasMetadata());
64 });
65}
66
68 return MAI.Reqs.getExtensions().contains(
69 SPIRV::Extension::SPV_KHR_relaxed_extended_instruction);
70}
71
73 : Asm(AP), Mod(M) {
74 assert(spirvPreserveAuxData(M.getTargetTriple()) &&
75 "AuxData handler created with AuxData preservation disabled");
76 for (const GlobalObject &GO : M.global_objects())
78 LinkagePreservedGOs.push_back(&GO);
79}
80
82 return SPVPreserveAuxData || TT.getVendor() == Triple::VendorType::AMD;
83}
84
87 if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_non_semantic_info))
88 reportFatalUsageError("-spirv-preserve-auxdata requires the "
89 "SPV_KHR_non_semantic_info extension to be enabled.");
90 MAI.Reqs.addExtension(SPIRV::Extension::SPV_KHR_non_semantic_info);
91 if (!MAI.ExtInstSetMap.contains(NonSemanticAuxDataSet))
92 MAI.ExtInstSetMap[NonSemanticAuxDataSet] = MAI.getNextIDRegister();
93
94 // Drop NonSemantic forward references if
95 // SPV_KHR_relaxed_extended_instruction not enabled.
96 if (MAI.InstrAuxDataRecords.empty() && !hasFunctionAuxData(Mod))
97 return;
98 if (ST.canUseExtension(
99 SPIRV::Extension::SPV_KHR_relaxed_extended_instruction))
100 MAI.Reqs.addExtension(
101 SPIRV::Extension::SPV_KHR_relaxed_extended_instruction);
102 else
103 MAI.InstrAuxDataRecords.clear();
104}
105
107SPIRVAuxDataHandler::getOrEmitString(StringRef S,
109 auto [It, Inserted] = StringRegs.try_emplace(S);
110 if (!Inserted)
111 return It->second;
112 MCRegister Reg = MAI.getNextIDRegister();
113 It->second = Reg;
114 MCInst Inst;
115 Inst.setOpcode(SPIRV::OpString);
117 addStringImm(S, Inst);
118 emitMCInst(Inst);
119 return Reg;
120}
121
122void SPIRVAuxDataHandler::collectAttributesFor(const GlobalObject *GO,
126 for (const Attribute &A : getGOAttrs(GO)) {
127 if (A.isStringAttribute() &&
128 A.getKindAsString() == SPIRV_WAS_AVAILABLE_EXTERNALLY_ATTR)
129 continue;
130 ExtInstRecord Rec;
131 Rec.Opcode = Opcode;
132 Rec.Target = GO;
133 if (A.isStringAttribute()) {
134 Rec.Operands.push_back({getOrEmitString(A.getKindAsString(), MAI)});
135 StringRef Val = A.getValueAsString();
136 if (!Val.empty())
137 Rec.Operands.push_back({getOrEmitString(Val, MAI)});
138 } else {
139 Rec.Operands.push_back(
140 {getOrEmitString(StringPool.save(A.getAsString()), MAI)});
141 }
142 PendingRecords.push_back(std::move(Rec));
143 }
144}
145
146void SPIRVAuxDataHandler::collectMetadataFor(const GlobalObject *GO,
147 ArrayRef<StringRef> MDNames,
150 GO->getAllMetadata(AllMD);
151 if (AllMD.empty())
152 return;
153 AuxDataOpcode Opcode =
155 // MDString operands become OpStrings; ValueAsMetadata constants (e.g.
156 // !{i32 5}) become OpConstants emitted at section 10. Any other operand
157 // kind would need full value translation, so skip the whole node.
158 auto CollectOperands =
159 [&](MDNode *MD) -> std::optional<SmallVector<Operand, 4>> {
160 SmallVector<Operand, 4> Out;
161 for (const MDOperand &MdOp : MD->operands()) {
162 Metadata *Md = MdOp.get();
163 if (auto *MDStr = dyn_cast_or_null<MDString>(Md)) {
164 Out.push_back({getOrEmitString(MDStr->getString(), MAI)});
165 } else if (auto *VAM = dyn_cast_or_null<ValueAsMetadata>(Md)) {
166 auto *C = dyn_cast<Constant>(VAM->getValue());
167 if (!C || !(isa<ConstantInt>(C) || isa<ConstantFP>(C)))
168 return std::nullopt;
169 Out.push_back({MCRegister(), C});
170 } else {
171 return std::nullopt;
172 }
173 }
174 return Out;
175 };
176 for (const auto &MD : AllMD) {
177 if (MD.first == LLVMContext::MD_dbg)
178 continue;
179 StringRef MDName = MDNames[MD.first];
180 if (MDName == "spirv.Decorations" || MDName == "spirv.ParameterDecorations")
181 continue;
182 auto Operands = CollectOperands(MD.second);
183 if (!Operands)
184 continue;
185 ExtInstRecord Rec;
186 Rec.Opcode = Opcode;
187 Rec.Target = GO;
188 Rec.Operands.push_back({getOrEmitString(MDName, MAI)});
189 Rec.Operands.append(Operands->begin(), Operands->end());
190 PendingRecords.push_back(std::move(Rec));
191 }
192}
193
195 if (!MAI.getExtInstSetReg(NonSemanticAuxDataSet).isValid())
196 return;
197 // One OpString per metadata kind; stop scanning once every kind is seen.
198 constexpr unsigned AllMDKindsSeen =
199 (1u << (static_cast<unsigned>(
201 1)) -
202 1;
203 unsigned SeenMask = 0;
204 for (const auto &Rec : MAI.InstrAuxDataRecords) {
205 unsigned Bit = 1u << static_cast<unsigned>(Rec.Kind);
206 if (SeenMask & Bit)
207 continue;
208 SeenMask |= Bit;
209 getOrEmitString(MAI.getAMDGPUAtomicMDName(Rec.Kind), MAI);
210 if (SeenMask == AllMDKindsSeen)
211 break;
212 }
214 Mod.getContext().getMDKindNames(MDNames);
215 bool CanUseForwardRefs = canUseForwardRefs(MAI);
216 for (const GlobalObject &GO : Mod.global_objects()) {
217 if (GO.isDeclaration() || (isa<Function>(GO) && !CanUseForwardRefs))
218 continue;
219 collectAttributesFor(&GO, MAI);
220 collectMetadataFor(&GO, MDNames, MAI);
221 }
222}
223
225 MCRegister ExtSetReg = MAI.getExtInstSetReg(NonSemanticAuxDataSet);
226 if (!ExtSetReg.isValid())
227 return;
228
229 MCRegister VoidTypeReg = findOrEmitOpTypeVoid(MAI);
230
231 for (const ExtInstRecord &Rec : PendingRecords) {
232 MCRegister TargetReg = MAI.getGlobalObjReg(Rec.Target);
233 if (!TargetReg.isValid())
234 continue;
236 Operands.push_back(TargetReg);
237 for (const Operand &Op : Rec.Operands)
238 Operands.push_back(Op.Const ? emitConstant(Op.Const, MAI) : Op.Reg);
239 emitAuxDataExtInst(Rec.Opcode, VoidTypeReg, ExtSetReg, Operands, MAI,
240 /*UseForwardRefs=*/isa<Function>(Rec.Target));
241 }
242
243 for (const auto &Rec : MAI.InstrAuxDataRecords) {
244 MCRegister TargetReg = MAI.getRegisterAlias(Rec.MF, Rec.TargetReg);
245 if (!TargetReg.isValid())
246 continue;
247 MCRegister MDNameReg =
248 getOrEmitString(MAI.getAMDGPUAtomicMDName(Rec.Kind), MAI);
249 // TargetReg is defined in a function body, emitted after this section, so
250 // it is always a forward reference.
251 emitAuxDataExtInst(InstructionMetadataOpcode, VoidTypeReg, ExtSetReg,
252 {TargetReg, MDNameReg}, MAI, /*UseForwardRefs=*/true);
253 }
254
255 if (LinkagePreservedGOs.empty())
256 return;
257
258 MCRegister UInt32TypeReg = findOrEmitOpTypeUInt32(MAI);
259 MCRegister AEConstReg;
260 bool CanUseForwardRefs = canUseForwardRefs(MAI);
261 for (const GlobalObject *GO : LinkagePreservedGOs) {
262 if (isa<Function>(GO) && !CanUseForwardRefs)
263 continue;
264 MCRegister TargetReg = MAI.getGlobalObjReg(GO);
265 if (!TargetReg.isValid())
266 continue;
267 if (!AEConstReg.isValid())
268 AEConstReg =
269 emitOpConstantUInt32(AvailableExternally, UInt32TypeReg, MAI);
270 emitAuxDataExtInst(LinkageOpcode, VoidTypeReg, ExtSetReg,
271 {TargetReg, AEConstReg}, MAI,
272 /*UseForwardRefs=*/isa<Function>(GO));
273 }
274}
275
276void SPIRVAuxDataHandler::emitAuxDataExtInst(AuxDataOpcode Opcode,
277 MCRegister VoidTypeReg,
278 MCRegister ExtSetReg,
281 bool UseForwardRefs) {
282 MCInst Inst;
283 Inst.setOpcode(UseForwardRefs ? SPIRV::OpExtInstWithForwardRefsKHR
284 : SPIRV::OpExtInst);
286 Inst.addOperand(MCOperand::createReg(VoidTypeReg));
287 Inst.addOperand(MCOperand::createReg(ExtSetReg));
288 Inst.addOperand(MCOperand::createImm(Opcode));
289 for (MCRegister R : Operands)
291 emitMCInst(Inst);
292}
293
294void SPIRVAuxDataHandler::emitMCInst(MCInst &Inst) {
295 Asm.OutStreamer->emitInstruction(Inst, Asm.getSubtargetInfo());
296}
297
299SPIRVAuxDataHandler::findOrEmitOpTypeVoid(SPIRV::ModuleAnalysisInfo &MAI) {
300 for (const MachineInstr *MI : MAI.getMSInstrs(SPIRV::MB_TypeConstVars))
301 if (MI->getOpcode() == SPIRV::OpTypeVoid)
302 return MAI.getRegisterAlias(MI->getMF(), MI->getOperand(0).getReg());
303 MCRegister Reg = MAI.getNextIDRegister();
304 MCInst Inst;
305 Inst.setOpcode(SPIRV::OpTypeVoid);
307 emitMCInst(Inst);
308 return Reg;
309}
310
312SPIRVAuxDataHandler::findOrEmitOpTypeInt(unsigned BitWidth,
314 // SPIR-V OpTypeInt: <width>, <signedness>. Signedness 0 = unsigned, 1 =
315 // signed; we always emit unsigned.
316 constexpr int64_t UnsignedSignedness = 0;
317 for (const MachineInstr *MI : MAI.getMSInstrs(SPIRV::MB_TypeConstVars))
318 if (MI->getOpcode() == SPIRV::OpTypeInt &&
319 MI->getOperand(1).getImm() == static_cast<int64_t>(BitWidth) &&
320 MI->getOperand(2).getImm() == UnsignedSignedness)
321 return MAI.getRegisterAlias(MI->getMF(), MI->getOperand(0).getReg());
322 MCRegister Reg = MAI.getNextIDRegister();
323 MCInst Inst;
324 Inst.setOpcode(SPIRV::OpTypeInt);
327 Inst.addOperand(MCOperand::createImm(UnsignedSignedness));
328 emitMCInst(Inst);
329 return Reg;
330}
331
333SPIRVAuxDataHandler::findOrEmitOpTypeUInt32(SPIRV::ModuleAnalysisInfo &MAI) {
334 return findOrEmitOpTypeInt(32, MAI);
335}
336
338SPIRVAuxDataHandler::findOrEmitOpTypeFloat(unsigned BitWidth,
340 for (const MachineInstr *MI : MAI.getMSInstrs(SPIRV::MB_TypeConstVars))
341 if (MI->getOpcode() == SPIRV::OpTypeFloat &&
342 MI->getOperand(1).getImm() == static_cast<int64_t>(BitWidth))
343 return MAI.getRegisterAlias(MI->getMF(), MI->getOperand(0).getReg());
344 MCRegister Reg = MAI.getNextIDRegister();
345 MCInst Inst;
346 Inst.setOpcode(SPIRV::OpTypeFloat);
349 emitMCInst(Inst);
350 return Reg;
351}
352
353MCRegister SPIRVAuxDataHandler::emitConstant(const Constant *C,
355 auto [It, Inserted] = ConstantRegs.try_emplace(C);
356 if (!Inserted)
357 return It->second;
358
359 APInt Bits;
360 unsigned Opcode;
361 MCRegister TypeReg;
362 if (const auto *CI = dyn_cast<ConstantInt>(C)) {
363 Bits = CI->getValue();
364 Opcode = SPIRV::OpConstantI;
365 TypeReg = findOrEmitOpTypeInt(Bits.getBitWidth(), MAI);
366 } else {
367 const auto *CF = cast<ConstantFP>(C);
368 Bits = CF->getValueAPF().bitcastToAPInt();
369 Opcode = SPIRV::OpConstantF;
370 TypeReg = findOrEmitOpTypeFloat(Bits.getBitWidth(), MAI);
371 }
372
373 MCRegister Reg = MAI.getNextIDRegister();
374 It->second = Reg;
375 MCInst Inst;
376 Inst.setOpcode(Opcode);
378 Inst.addOperand(MCOperand::createReg(TypeReg));
379 // SPIR-V encodes the literal as ceil(width/32) little-endian 32-bit words.
380 unsigned NumWords = divideCeil(Bits.getBitWidth(), 32);
381 for (unsigned I = 0; I < NumWords; ++I)
382 Inst.addOperand(MCOperand::createImm(Bits.extractBitsAsZExtValue(
383 std::min(32u, Bits.getBitWidth() - I * 32), I * 32)));
384 // The asm printer needs this hint to render an f16 literal correctly.
385 if (Opcode == SPIRV::OpConstantF && Bits.getBitWidth() == 16)
387 emitMCInst(Inst);
388 return Reg;
389}
390
391MCRegister SPIRVAuxDataHandler::emitOpConstantUInt32(
392 uint32_t Value, MCRegister UInt32TypeReg, SPIRV::ModuleAnalysisInfo &MAI) {
393 MCRegister Reg = MAI.getNextIDRegister();
394 MCInst Inst;
395 Inst.setOpcode(SPIRV::OpConstantI);
397 Inst.addOperand(MCOperand::createReg(UInt32TypeReg));
398 Inst.addOperand(MCOperand::createImm(static_cast<int64_t>(Value)));
399 emitMCInst(Inst);
400 return Reg;
401}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
This file contains the simple types necessary to represent the attributes associated with functions a...
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
This file contains the declarations for the subclasses of Constant, which represent the different fla...
dxil translate DXIL Translate Metadata
IRTranslator LLVM IR MI
Module.h This file contains the declarations for the Module class.
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
Register Reg
This file contains the declarations for metadata subclasses.
SI Fold Operands
static bool canUseForwardRefs(const SPIRV::ModuleAnalysisInfo &MAI)
static cl::opt< bool > SPVPreserveAuxData("spirv-preserve-auxdata", cl::desc("Preserve LLVM attributes and metadata as " "NonSemantic.AuxData ExtInst annotations (requires " "SPV_KHR_non_semantic_info)"), cl::Hidden, cl::init(false))
static bool wasAvailableExternally(const GlobalObject *GO)
static bool hasFunctionAuxData(const Module &M)
#define SPIRV_WAS_AVAILABLE_EXTERNALLY_ATTR
Definition SPIRVUtils.h:566
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
This class is intended to be used as a driving class for all asm writers.
Definition AsmPrinter.h:95
std::unique_ptr< MCStreamer > OutStreamer
This is the MCStreamer object for the file we are generating.
Definition AsmPrinter.h:110
const MCSubtargetInfo & getSubtargetInfo() const
Return information about subtarget.
This class holds the attributes for a particular argument, parameter, function, or return value.
Definition Attributes.h:410
Functions, function parameters, and return types can have attributes to indicate how they should be t...
Definition Attributes.h:106
This is an important base class in LLVM.
Definition Constant.h:43
LLVM_ABI void getAllMetadata(SmallVectorImpl< std::pair< unsigned, MDNode * > > &MDs) const
Appends all metadata attached to this value to MDs, sorting by KindID.
LLVM_ABI bool isDeclaration() const
Return true if the primary definition of this global value is outside of the current translation unit...
Definition Globals.cpp:408
Instances of this class represent a single low-level machine instruction.
Definition MCInst.h:188
void setFlags(unsigned F)
Definition MCInst.h:204
void addOperand(const MCOperand Op)
Definition MCInst.h:215
void setOpcode(unsigned Op)
Definition MCInst.h:201
static MCOperand createReg(MCRegister Reg)
Definition MCInst.h:138
static MCOperand createImm(int64_t Val)
Definition MCInst.h:145
Wrapper class representing physical registers. Should be passed by value.
Definition MCRegister.h:41
constexpr bool isValid() const
Definition MCRegister.h:84
A Module instance is used to store all the information related to an LLVM module.
Definition Module.h:68
SPIRVAuxDataHandler(AsmPrinter &AP, const Module &M)
void emitAuxDataStrings(SPIRV::ModuleAnalysisInfo &MAI)
Emit OpStrings and stage ExtInst records; call in module section 7.
void emitAuxData(SPIRV::ModuleAnalysisInfo &MAI)
Emit the staged ExtInst records; call in module section 10.
void prepareModuleOutput(const SPIRVSubtarget &ST, SPIRV::ModuleAnalysisInfo &MAI)
Register extension + ext-inst-set; call before output of section 1.
bool contains(const T &V) const
Check if the SmallSet contains the given element.
Definition SmallSet.h:229
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.
Definition StringRef.h:56
constexpr bool empty() const
Check if the string is empty.
Definition StringRef.h:141
Triple - Helper class for working with autoconf configuration names.
Definition Triple.h:48
LLVM Value Representation.
Definition Value.h:75
initializer< Ty > init(const Ty &Val)
This is an optimization pass for GlobalISel generic memory operations.
void addStringImm(StringRef Str, MCInst &Inst)
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
@ GlobalVariableMetadataOpcode
@ FunctionAttributeOpcode
@ GlobalVariableAttributeOpcode
@ InstructionMetadataOpcode
@ FunctionMetadataOpcode
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
Definition InstrProf.h:143
auto dyn_cast_or_null(const Y &Val)
Definition Casting.h:753
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1762
bool spirvPreserveAuxData(const Triple &TT)
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...
Definition Casting.h:547
constexpr T divideCeil(U Numerator, V Denominator)
Returns the integer ceil(Numerator / Denominator).
Definition MathExtras.h:389
DWARFExpression::Operation Op
constexpr unsigned BitWidth
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
LLVM_ABI void reportFatalUsageError(Error Err)
Report a fatal error that does not indicate a bug in LLVM.
Definition Error.cpp:177
MCRegister getExtInstSetReg(unsigned SetNum)
DenseMap< unsigned, MCRegister > ExtInstSetMap
InstrList & getMSInstrs(unsigned MSType)
MCRegister getRegisterAlias(const MachineFunction *MF, Register Reg)
SmallVector< InstrAuxDataRecord > InstrAuxDataRecords
static StringRef getAMDGPUAtomicMDName(AMDGPUAtomicMDKind Kind)
MCRegister getGlobalObjReg(const GlobalObject *GO)
void addExtension(Extension::Extension ToAdd)
const SmallSet< Extension::Extension, 4 > & getExtensions() const