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"
26
27using namespace llvm;
28
29namespace {
30enum AuxDataLinkageType : uint32_t {
31 AvailableExternally = 0,
32};
33
34constexpr unsigned NonSemanticAuxDataSet =
35 static_cast<unsigned>(SPIRV::InstructionSet::NonSemantic_AuxData);
36
37AttributeSet getGOAttrs(const GlobalObject *GO) {
38 if (const auto *F = dyn_cast<Function>(GO))
39 return F->getAttributes().getFnAttrs();
40 return cast<GlobalVariable>(GO)->getAttributes();
41}
42} // namespace
43
44static bool wasAvailableExternally(const GlobalObject *GO) {
45 if (const auto *F = dyn_cast<Function>(GO))
46 return F->hasFnAttribute(SPIRV_WAS_AVAILABLE_EXTERNALLY_ATTR);
47 return cast<GlobalVariable>(GO)->getAttributes().hasAttribute(
49}
50
51// Return true if any function definition may get an AuxData record.
52static bool hasFunctionAuxData(const Module &M) {
53 return any_of(M.functions(), [](const Function &F) {
54 return !F.isDeclaration() &&
55 (F.getAttributes().hasFnAttrs() || F.hasMetadata());
56 });
57}
58
60 return MAI.Reqs.getExtensions().contains(
61 SPIRV::Extension::SPV_KHR_relaxed_extended_instruction);
62}
63
65 : Asm(AP), Mod(M) {
66 for (const GlobalObject &GO : M.global_objects())
68 LinkagePreservedGOs.push_back(&GO);
69}
70
71bool llvm::spirvPreserveAuxData(const SPIRVOptions &CLOpts, const Triple &TT) {
72 return CLOpts.preserve_auxdata || TT.getVendor() == Triple::VendorType::AMD;
73}
74
77 if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_non_semantic_info))
78 reportFatalUsageError("-spirv-preserve-auxdata requires the "
79 "SPV_KHR_non_semantic_info extension to be enabled.");
80 MAI.Reqs.addExtension(SPIRV::Extension::SPV_KHR_non_semantic_info);
81 if (!MAI.ExtInstSetMap.contains(NonSemanticAuxDataSet))
82 MAI.ExtInstSetMap[NonSemanticAuxDataSet] = MAI.getNextIDRegister();
83
84 // Drop NonSemantic forward references if
85 // SPV_KHR_relaxed_extended_instruction not enabled.
86 if (MAI.InstrAuxDataRecords.empty() && !hasFunctionAuxData(Mod))
87 return;
88 if (ST.canUseExtension(
89 SPIRV::Extension::SPV_KHR_relaxed_extended_instruction))
91 SPIRV::Extension::SPV_KHR_relaxed_extended_instruction);
92 else
93 MAI.InstrAuxDataRecords.clear();
94}
95
97SPIRVAuxDataHandler::getOrEmitString(StringRef S,
99 auto [It, Inserted] = StringRegs.try_emplace(S);
100 if (!Inserted)
101 return It->second;
102 MCRegister Reg = MAI.getNextIDRegister();
103 It->second = Reg;
104 MCInst Inst;
105 Inst.setOpcode(SPIRV::OpString);
107 addStringImm(S, Inst);
108 emitMCInst(Inst);
109 return Reg;
110}
111
112void SPIRVAuxDataHandler::collectAttributesFor(const GlobalObject *GO,
116 for (const Attribute &A : getGOAttrs(GO)) {
117 if (A.isStringAttribute() &&
118 A.getKindAsString() == SPIRV_WAS_AVAILABLE_EXTERNALLY_ATTR)
119 continue;
120 ExtInstRecord Rec;
121 Rec.Opcode = Opcode;
122 Rec.Target = GO;
123 if (A.isStringAttribute()) {
124 Rec.Operands.push_back({getOrEmitString(A.getKindAsString(), MAI)});
125 StringRef Val = A.getValueAsString();
126 if (!Val.empty())
127 Rec.Operands.push_back({getOrEmitString(Val, MAI)});
128 } else {
129 Rec.Operands.push_back(
130 {getOrEmitString(StringPool.save(A.getAsString()), MAI)});
131 }
132 PendingRecords.push_back(std::move(Rec));
133 }
134}
135
136void SPIRVAuxDataHandler::collectMetadataFor(const GlobalObject *GO,
137 ArrayRef<StringRef> MDNames,
140 GO->getAllMetadata(AllMD);
141 if (AllMD.empty())
142 return;
143 AuxDataOpcode Opcode =
145 // MDString operands become OpStrings; ValueAsMetadata constants (e.g.
146 // !{i32 5}) become OpConstants emitted at section 10. Any other operand
147 // kind would need full value translation, so skip the whole node.
148 auto CollectOperands =
149 [&](MDNode *MD) -> std::optional<SmallVector<Operand, 4>> {
150 SmallVector<Operand, 4> Out;
151 for (const MDOperand &MdOp : MD->operands()) {
152 Metadata *Md = MdOp.get();
153 if (auto *MDStr = dyn_cast_or_null<MDString>(Md)) {
154 Out.push_back({getOrEmitString(MDStr->getString(), MAI)});
155 } else if (auto *VAM = dyn_cast_or_null<ValueAsMetadata>(Md)) {
156 auto *C = dyn_cast<Constant>(VAM->getValue());
157 if (!C || !(isa<ConstantInt>(C) || isa<ConstantFP>(C)))
158 return std::nullopt;
159 Out.push_back({MCRegister(), C});
160 } else {
161 return std::nullopt;
162 }
163 }
164 return Out;
165 };
166 for (const auto &MD : AllMD) {
167 if (MD.first == LLVMContext::MD_dbg)
168 continue;
169 StringRef MDName = MDNames[MD.first];
170 if (MDName == "spirv.Decorations" || MDName == "spirv.ParameterDecorations")
171 continue;
172 auto Operands = CollectOperands(MD.second);
173 if (!Operands)
174 continue;
175 ExtInstRecord Rec;
176 Rec.Opcode = Opcode;
177 Rec.Target = GO;
178 Rec.Operands.push_back({getOrEmitString(MDName, MAI)});
179 Rec.Operands.append(Operands->begin(), Operands->end());
180 PendingRecords.push_back(std::move(Rec));
181 }
182}
183
185 if (!MAI.getExtInstSetReg(NonSemanticAuxDataSet).isValid())
186 return;
187 // One OpString per metadata kind; stop scanning once every kind is seen.
188 constexpr unsigned AllMDKindsSeen =
189 (1u << (static_cast<unsigned>(
191 1)) -
192 1;
193 unsigned SeenMask = 0;
194 for (const auto &Rec : MAI.InstrAuxDataRecords) {
195 unsigned Bit = 1u << static_cast<unsigned>(Rec.Kind);
196 if (SeenMask & Bit)
197 continue;
198 SeenMask |= Bit;
199 getOrEmitString(MAI.getAMDGPUAtomicMDName(Rec.Kind), MAI);
200 if (SeenMask == AllMDKindsSeen)
201 break;
202 }
204 Mod.getContext().getMDKindNames(MDNames);
205 bool CanUseForwardRefs = canUseForwardRefs(MAI);
206 for (const GlobalObject &GO : Mod.global_objects()) {
207 if (GO.isDeclaration() || (isa<Function>(GO) && !CanUseForwardRefs))
208 continue;
209 collectAttributesFor(&GO, MAI);
210 collectMetadataFor(&GO, MDNames, MAI);
211 }
212}
213
215 MCRegister ExtSetReg = MAI.getExtInstSetReg(NonSemanticAuxDataSet);
216 if (!ExtSetReg.isValid())
217 return;
218
219 MCRegister VoidTypeReg = findOrEmitOpTypeVoid(MAI);
220
221 for (const ExtInstRecord &Rec : PendingRecords) {
222 MCRegister TargetReg = MAI.getGlobalObjReg(Rec.Target);
223 if (!TargetReg.isValid())
224 continue;
226 Operands.push_back(TargetReg);
227 for (const Operand &Op : Rec.Operands)
228 Operands.push_back(Op.Const ? emitConstant(Op.Const, MAI) : Op.Reg);
229 emitAuxDataExtInst(Rec.Opcode, VoidTypeReg, ExtSetReg, Operands, MAI,
230 /*UseForwardRefs=*/isa<Function>(Rec.Target));
231 }
232
233 for (const auto &Rec : MAI.InstrAuxDataRecords) {
234 MCRegister TargetReg = MAI.getRegisterAlias(Rec.MF, Rec.TargetReg);
235 if (!TargetReg.isValid())
236 continue;
237 MCRegister MDNameReg =
238 getOrEmitString(MAI.getAMDGPUAtomicMDName(Rec.Kind), MAI);
239 // TargetReg is defined in a function body, emitted after this section, so
240 // it is always a forward reference.
241 emitAuxDataExtInst(InstructionMetadataOpcode, VoidTypeReg, ExtSetReg,
242 {TargetReg, MDNameReg}, MAI, /*UseForwardRefs=*/true);
243 }
244
245 if (LinkagePreservedGOs.empty())
246 return;
247
248 MCRegister UInt32TypeReg = findOrEmitOpTypeUInt32(MAI);
249 MCRegister AEConstReg;
250 bool CanUseForwardRefs = canUseForwardRefs(MAI);
251 for (const GlobalObject *GO : LinkagePreservedGOs) {
252 if (isa<Function>(GO) && !CanUseForwardRefs)
253 continue;
254 MCRegister TargetReg = MAI.getGlobalObjReg(GO);
255 if (!TargetReg.isValid())
256 continue;
257 if (!AEConstReg.isValid())
258 AEConstReg =
259 emitOpConstantUInt32(AvailableExternally, UInt32TypeReg, MAI);
260 emitAuxDataExtInst(LinkageOpcode, VoidTypeReg, ExtSetReg,
261 {TargetReg, AEConstReg}, MAI,
262 /*UseForwardRefs=*/isa<Function>(GO));
263 }
264}
265
266void SPIRVAuxDataHandler::emitAuxDataExtInst(AuxDataOpcode Opcode,
267 MCRegister VoidTypeReg,
268 MCRegister ExtSetReg,
271 bool UseForwardRefs) {
272 MCInst Inst;
273 Inst.setOpcode(UseForwardRefs ? SPIRV::OpExtInstWithForwardRefsKHR
274 : SPIRV::OpExtInst);
276 Inst.addOperand(MCOperand::createReg(VoidTypeReg));
277 Inst.addOperand(MCOperand::createReg(ExtSetReg));
278 Inst.addOperand(MCOperand::createImm(Opcode));
279 for (MCRegister R : Operands)
281 emitMCInst(Inst);
282}
283
284void SPIRVAuxDataHandler::emitMCInst(MCInst &Inst) {
285 Asm.OutStreamer->emitInstruction(Inst, Asm.getSubtargetInfo());
286}
287
289SPIRVAuxDataHandler::findOrEmitOpTypeVoid(SPIRV::ModuleAnalysisInfo &MAI) {
290 for (const MachineInstr *MI : MAI.getMSInstrs(SPIRV::MB_TypeConstVars))
291 if (MI->getOpcode() == SPIRV::OpTypeVoid)
292 return MAI.getRegisterAlias(MI->getMF(), MI->getOperand(0).getReg());
293 MCRegister Reg = MAI.getNextIDRegister();
294 MCInst Inst;
295 Inst.setOpcode(SPIRV::OpTypeVoid);
297 emitMCInst(Inst);
298 return Reg;
299}
300
302SPIRVAuxDataHandler::findOrEmitOpTypeInt(unsigned BitWidth,
304 // SPIR-V OpTypeInt: <width>, <signedness>. Signedness 0 = unsigned, 1 =
305 // signed; we always emit unsigned.
306 constexpr int64_t UnsignedSignedness = 0;
307 for (const MachineInstr *MI : MAI.getMSInstrs(SPIRV::MB_TypeConstVars))
308 if (MI->getOpcode() == SPIRV::OpTypeInt &&
309 MI->getOperand(1).getImm() == static_cast<int64_t>(BitWidth) &&
310 MI->getOperand(2).getImm() == UnsignedSignedness)
311 return MAI.getRegisterAlias(MI->getMF(), MI->getOperand(0).getReg());
312 MCRegister Reg = MAI.getNextIDRegister();
313 MCInst Inst;
314 Inst.setOpcode(SPIRV::OpTypeInt);
317 Inst.addOperand(MCOperand::createImm(UnsignedSignedness));
318 emitMCInst(Inst);
319 return Reg;
320}
321
323SPIRVAuxDataHandler::findOrEmitOpTypeUInt32(SPIRV::ModuleAnalysisInfo &MAI) {
324 return findOrEmitOpTypeInt(32, MAI);
325}
326
328SPIRVAuxDataHandler::findOrEmitOpTypeFloat(unsigned BitWidth,
330 for (const MachineInstr *MI : MAI.getMSInstrs(SPIRV::MB_TypeConstVars))
331 if (MI->getOpcode() == SPIRV::OpTypeFloat &&
332 MI->getOperand(1).getImm() == static_cast<int64_t>(BitWidth))
333 return MAI.getRegisterAlias(MI->getMF(), MI->getOperand(0).getReg());
334 MCRegister Reg = MAI.getNextIDRegister();
335 MCInst Inst;
336 Inst.setOpcode(SPIRV::OpTypeFloat);
339 emitMCInst(Inst);
340 return Reg;
341}
342
343MCRegister SPIRVAuxDataHandler::emitConstant(const Constant *C,
345 auto [It, Inserted] = ConstantRegs.try_emplace(C);
346 if (!Inserted)
347 return It->second;
348
349 APInt Bits;
350 unsigned Opcode;
351 MCRegister TypeReg;
352 if (const auto *CI = dyn_cast<ConstantInt>(C)) {
353 Bits = CI->getValue();
354 Opcode = SPIRV::OpConstantI;
355 TypeReg = findOrEmitOpTypeInt(Bits.getBitWidth(), MAI);
356 } else {
357 const auto *CF = cast<ConstantFP>(C);
358 Bits = CF->getValueAPF().bitcastToAPInt();
359 Opcode = SPIRV::OpConstantF;
360 TypeReg = findOrEmitOpTypeFloat(Bits.getBitWidth(), MAI);
361 }
362
363 MCRegister Reg = MAI.getNextIDRegister();
364 It->second = Reg;
365 MCInst Inst;
366 Inst.setOpcode(Opcode);
368 Inst.addOperand(MCOperand::createReg(TypeReg));
369 // SPIR-V encodes the literal as ceil(width/32) little-endian 32-bit words.
370 unsigned NumWords = divideCeil(Bits.getBitWidth(), 32);
371 for (unsigned I = 0; I < NumWords; ++I)
372 Inst.addOperand(MCOperand::createImm(Bits.extractBitsAsZExtValue(
373 std::min(32u, Bits.getBitWidth() - I * 32), I * 32)));
374 // The asm printer needs this hint to render an f16 literal correctly.
375 if (Opcode == SPIRV::OpConstantF && Bits.getBitWidth() == 16)
377 emitMCInst(Inst);
378 return Reg;
379}
380
381MCRegister SPIRVAuxDataHandler::emitOpConstantUInt32(
382 uint32_t Value, MCRegister UInt32TypeReg, SPIRV::ModuleAnalysisInfo &MAI) {
383 MCRegister Reg = MAI.getNextIDRegister();
384 MCInst Inst;
385 Inst.setOpcode(SPIRV::OpConstantI);
387 Inst.addOperand(MCOperand::createReg(UInt32TypeReg));
388 Inst.addOperand(MCOperand::createImm(static_cast<int64_t>(Value)));
389 emitMCInst(Inst);
390 return Reg;
391}
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.
if(PassOpts->AAPipeline)
SI Fold Operands
static bool canUseForwardRefs(const SPIRV::ModuleAnalysisInfo &MAI)
static bool wasAvailableExternally(const GlobalObject *GO)
static bool hasFunctionAuxData(const Module &M)
#define SPIRV_WAS_AVAILABLE_EXTERNALLY_ATTR
Definition SPIRVUtils.h:559
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:406
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:44
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
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
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
bool spirvPreserveAuxData(const SPIRVOptions &CLOpts, const Triple &TT)
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