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
60 : Asm(AP), Mod(M) {
61 for (const GlobalObject &GO : M.global_objects())
63 LinkagePreservedGOs.push_back(&GO);
64}
65
67 return SPVPreserveAuxData ||
68 Mod.getTargetTriple().getVendor() == Triple::VendorType::AMD;
69}
70
73 if (!hasWork())
74 return;
75 if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_non_semantic_info)) {
77 report_fatal_error("-spirv-preserve-auxdata requires the "
78 "SPV_KHR_non_semantic_info extension to be enabled.");
79 return;
80 }
81 MAI.Reqs.addExtension(SPIRV::Extension::SPV_KHR_non_semantic_info);
82 if (!MAI.ExtInstSetMap.count(NonSemanticAuxDataSet))
83 MAI.ExtInstSetMap[NonSemanticAuxDataSet] = MAI.getNextIDRegister();
84}
85
87SPIRVAuxDataHandler::getOrEmitString(StringRef S,
89 auto [It, Inserted] = StringRegs.try_emplace(S);
90 if (!Inserted)
91 return It->second;
92 MCRegister Reg = MAI.getNextIDRegister();
93 It->second = Reg;
94 MCInst Inst;
95 Inst.setOpcode(SPIRV::OpString);
97 addStringImm(S, Inst);
98 emitMCInst(Inst);
99 return Reg;
100}
101
102void SPIRVAuxDataHandler::collectAttributesFor(const GlobalObject *GO,
106 for (const Attribute &A : getGOAttrs(GO)) {
107 if (A.isStringAttribute() &&
108 A.getKindAsString() == SPIRV_WAS_AVAILABLE_EXTERNALLY_ATTR)
109 continue;
110 ExtInstRecord Rec;
111 Rec.Opcode = Opcode;
112 Rec.Target = GO;
113 if (A.isStringAttribute()) {
114 Rec.Operands.push_back({getOrEmitString(A.getKindAsString(), MAI)});
115 StringRef Val = A.getValueAsString();
116 if (!Val.empty())
117 Rec.Operands.push_back({getOrEmitString(Val, MAI)});
118 } else {
119 Rec.Operands.push_back(
120 {getOrEmitString(StringPool.save(A.getAsString()), MAI)});
121 }
122 PendingRecords.push_back(std::move(Rec));
123 }
124}
125
126void SPIRVAuxDataHandler::collectMetadataFor(const GlobalObject *GO,
127 ArrayRef<StringRef> MDNames,
130 GO->getAllMetadata(AllMD);
131 if (AllMD.empty())
132 return;
133 AuxDataOpcode Opcode =
135 // MDString operands become OpStrings; ValueAsMetadata constants (e.g.
136 // !{i32 5}) become OpConstants emitted at section 10. Any other operand
137 // kind would need full value translation, so skip the whole node.
138 auto CollectOperands =
139 [&](MDNode *MD) -> std::optional<SmallVector<Operand, 4>> {
140 SmallVector<Operand, 4> Out;
141 for (const MDOperand &MdOp : MD->operands()) {
142 Metadata *Md = MdOp.get();
143 if (auto *MDStr = dyn_cast_or_null<MDString>(Md)) {
144 Out.push_back({getOrEmitString(MDStr->getString(), MAI)});
145 } else if (auto *VAM = dyn_cast_or_null<ValueAsMetadata>(Md)) {
146 auto *C = dyn_cast<Constant>(VAM->getValue());
147 if (!C || !(isa<ConstantInt>(C) || isa<ConstantFP>(C)))
148 return std::nullopt;
149 Out.push_back({MCRegister(), C});
150 } else {
151 return std::nullopt;
152 }
153 }
154 return Out;
155 };
156 for (const auto &MD : AllMD) {
157 if (MD.first == LLVMContext::MD_dbg)
158 continue;
159 StringRef MDName = MDNames[MD.first];
160 if (MDName == "spirv.Decorations" || MDName == "spirv.ParameterDecorations")
161 continue;
162 auto Operands = CollectOperands(MD.second);
163 if (!Operands)
164 continue;
165 ExtInstRecord Rec;
166 Rec.Opcode = Opcode;
167 Rec.Target = GO;
168 Rec.Operands.push_back({getOrEmitString(MDName, MAI)});
169 Rec.Operands.append(Operands->begin(), Operands->end());
170 PendingRecords.push_back(std::move(Rec));
171 }
172}
173
176 return;
177 if (!MAI.getExtInstSetReg(NonSemanticAuxDataSet).isValid())
178 return;
180 Mod.getContext().getMDKindNames(MDNames);
181 for (const GlobalObject &GO : Mod.global_objects()) {
182 if (GO.isDeclaration())
183 continue;
184 collectAttributesFor(&GO, MAI);
185 collectMetadataFor(&GO, MDNames, MAI);
186 }
187}
188
190 MCRegister ExtSetReg = MAI.getExtInstSetReg(NonSemanticAuxDataSet);
191 if (!ExtSetReg.isValid())
192 return;
193
194 MCRegister VoidTypeReg = findOrEmitOpTypeVoid(MAI);
195
196 for (const ExtInstRecord &Rec : PendingRecords) {
197 MCRegister TargetReg = MAI.getGlobalObjReg(Rec.Target);
198 if (!TargetReg.isValid())
199 continue;
201 Operands.push_back(TargetReg);
202 for (const Operand &Op : Rec.Operands)
203 Operands.push_back(Op.Const ? emitConstant(Op.Const, MAI) : Op.Reg);
204 emitAuxDataExtInst(Rec.Opcode, VoidTypeReg, ExtSetReg, Operands, MAI);
205 }
206
207 if (LinkagePreservedGOs.empty())
208 return;
209
210 MCRegister UInt32TypeReg = findOrEmitOpTypeUInt32(MAI);
211 MCRegister AEConstReg;
212 for (const GlobalObject *GO : LinkagePreservedGOs) {
213 MCRegister TargetReg = MAI.getGlobalObjReg(GO);
214 if (!TargetReg.isValid())
215 continue;
216 if (!AEConstReg.isValid())
217 AEConstReg =
218 emitOpConstantUInt32(AvailableExternally, UInt32TypeReg, MAI);
219 emitAuxDataExtInst(LinkageOpcode, VoidTypeReg, ExtSetReg,
220 {TargetReg, AEConstReg}, MAI);
221 }
222}
223
224void SPIRVAuxDataHandler::emitAuxDataExtInst(AuxDataOpcode Opcode,
225 MCRegister VoidTypeReg,
226 MCRegister ExtSetReg,
229 MCInst Inst;
230 Inst.setOpcode(SPIRV::OpExtInst);
232 Inst.addOperand(MCOperand::createReg(VoidTypeReg));
233 Inst.addOperand(MCOperand::createReg(ExtSetReg));
234 Inst.addOperand(MCOperand::createImm(Opcode));
235 for (MCRegister R : Operands)
237 emitMCInst(Inst);
238}
239
240void SPIRVAuxDataHandler::emitMCInst(MCInst &Inst) {
241 Asm.OutStreamer->emitInstruction(Inst, Asm.getSubtargetInfo());
242}
243
245SPIRVAuxDataHandler::findOrEmitOpTypeVoid(SPIRV::ModuleAnalysisInfo &MAI) {
246 for (const MachineInstr *MI : MAI.getMSInstrs(SPIRV::MB_TypeConstVars))
247 if (MI->getOpcode() == SPIRV::OpTypeVoid)
248 return MAI.getRegisterAlias(MI->getMF(), MI->getOperand(0).getReg());
249 MCRegister Reg = MAI.getNextIDRegister();
250 MCInst Inst;
251 Inst.setOpcode(SPIRV::OpTypeVoid);
253 emitMCInst(Inst);
254 return Reg;
255}
256
258SPIRVAuxDataHandler::findOrEmitOpTypeInt(unsigned BitWidth,
260 // SPIR-V OpTypeInt: <width>, <signedness>. Signedness 0 = unsigned, 1 =
261 // signed; we always emit unsigned.
262 constexpr int64_t UnsignedSignedness = 0;
263 for (const MachineInstr *MI : MAI.getMSInstrs(SPIRV::MB_TypeConstVars))
264 if (MI->getOpcode() == SPIRV::OpTypeInt &&
265 MI->getOperand(1).getImm() == static_cast<int64_t>(BitWidth) &&
266 MI->getOperand(2).getImm() == UnsignedSignedness)
267 return MAI.getRegisterAlias(MI->getMF(), MI->getOperand(0).getReg());
268 MCRegister Reg = MAI.getNextIDRegister();
269 MCInst Inst;
270 Inst.setOpcode(SPIRV::OpTypeInt);
273 Inst.addOperand(MCOperand::createImm(UnsignedSignedness));
274 emitMCInst(Inst);
275 return Reg;
276}
277
279SPIRVAuxDataHandler::findOrEmitOpTypeUInt32(SPIRV::ModuleAnalysisInfo &MAI) {
280 return findOrEmitOpTypeInt(32, MAI);
281}
282
284SPIRVAuxDataHandler::findOrEmitOpTypeFloat(unsigned BitWidth,
286 for (const MachineInstr *MI : MAI.getMSInstrs(SPIRV::MB_TypeConstVars))
287 if (MI->getOpcode() == SPIRV::OpTypeFloat &&
288 MI->getOperand(1).getImm() == static_cast<int64_t>(BitWidth))
289 return MAI.getRegisterAlias(MI->getMF(), MI->getOperand(0).getReg());
290 MCRegister Reg = MAI.getNextIDRegister();
291 MCInst Inst;
292 Inst.setOpcode(SPIRV::OpTypeFloat);
295 emitMCInst(Inst);
296 return Reg;
297}
298
299MCRegister SPIRVAuxDataHandler::emitConstant(const Constant *C,
301 auto [It, Inserted] = ConstantRegs.try_emplace(C);
302 if (!Inserted)
303 return It->second;
304
305 APInt Bits;
306 unsigned Opcode;
307 MCRegister TypeReg;
308 if (const auto *CI = dyn_cast<ConstantInt>(C)) {
309 Bits = CI->getValue();
310 Opcode = SPIRV::OpConstantI;
311 TypeReg = findOrEmitOpTypeInt(Bits.getBitWidth(), MAI);
312 } else {
313 const auto *CF = cast<ConstantFP>(C);
314 Bits = CF->getValueAPF().bitcastToAPInt();
315 Opcode = SPIRV::OpConstantF;
316 TypeReg = findOrEmitOpTypeFloat(Bits.getBitWidth(), MAI);
317 }
318
319 MCRegister Reg = MAI.getNextIDRegister();
320 It->second = Reg;
321 MCInst Inst;
322 Inst.setOpcode(Opcode);
324 Inst.addOperand(MCOperand::createReg(TypeReg));
325 // SPIR-V encodes the literal as ceil(width/32) little-endian 32-bit words.
326 unsigned NumWords = divideCeil(Bits.getBitWidth(), 32);
327 for (unsigned I = 0; I < NumWords; ++I)
328 Inst.addOperand(MCOperand::createImm(Bits.extractBitsAsZExtValue(
329 std::min(32u, Bits.getBitWidth() - I * 32), I * 32)));
330 // The asm printer needs this hint to render an f16 literal correctly.
331 if (Opcode == SPIRV::OpConstantF && Bits.getBitWidth() == 16)
333 emitMCInst(Inst);
334 return Reg;
335}
336
337MCRegister SPIRVAuxDataHandler::emitOpConstantUInt32(
338 uint32_t Value, MCRegister UInt32TypeReg, SPIRV::ModuleAnalysisInfo &MAI) {
339 MCRegister Reg = MAI.getNextIDRegister();
340 MCInst Inst;
341 Inst.setOpcode(SPIRV::OpConstantI);
343 Inst.addOperand(MCOperand::createReg(UInt32TypeReg));
344 Inst.addOperand(MCOperand::createImm(static_cast<int64_t>(Value)));
345 emitMCInst(Inst);
346 return Reg;
347}
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 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)
#define SPIRV_WAS_AVAILABLE_EXTERNALLY_ATTR
Definition SPIRVUtils.h:568
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:91
std::unique_ptr< MCStreamer > OutStreamer
This is the MCStreamer object for the file we are generating.
Definition AsmPrinter.h:106
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.
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
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
@ FunctionMetadataOpcode
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
Definition InstrProf.h:143
auto dyn_cast_or_null(const Y &Val)
Definition Casting.h:753
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
Definition Error.cpp:163
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
MCRegister getExtInstSetReg(unsigned SetNum)
DenseMap< unsigned, MCRegister > ExtInstSetMap
InstrList & getMSInstrs(unsigned MSType)
MCRegister getRegisterAlias(const MachineFunction *MF, Register Reg)
MCRegister getGlobalObjReg(const GlobalObject *GO)
void addExtension(Extension::Extension ToAdd)