LLVM 23.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)"),
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
70 if (!hasWork())
71 return;
72 if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_non_semantic_info)) {
74 report_fatal_error("-spirv-preserve-auxdata requires the "
75 "SPV_KHR_non_semantic_info extension to be enabled.");
76 return;
77 }
78 MAI.Reqs.addExtension(SPIRV::Extension::SPV_KHR_non_semantic_info);
79 if (!MAI.ExtInstSetMap.count(NonSemanticAuxDataSet))
80 MAI.ExtInstSetMap[NonSemanticAuxDataSet] = MAI.getNextIDRegister();
81}
82
84SPIRVAuxDataHandler::getOrEmitString(StringRef S,
86 auto [It, Inserted] = StringRegs.try_emplace(S);
87 if (!Inserted)
88 return It->second;
89 MCRegister Reg = MAI.getNextIDRegister();
90 It->second = Reg;
91 MCInst Inst;
92 Inst.setOpcode(SPIRV::OpString);
94 addStringImm(S, Inst);
95 emitMCInst(Inst);
96 return Reg;
97}
98
99void SPIRVAuxDataHandler::collectAttributesFor(const GlobalObject *GO,
103 for (const Attribute &A : getGOAttrs(GO)) {
104 if (A.isStringAttribute() &&
105 A.getKindAsString() == SPIRV_WAS_AVAILABLE_EXTERNALLY_ATTR)
106 continue;
107 ExtInstRecord Rec;
108 Rec.Opcode = Opcode;
109 Rec.Target = GO;
110 if (A.isStringAttribute()) {
111 Rec.Operands.push_back({getOrEmitString(A.getKindAsString(), MAI)});
112 StringRef Val = A.getValueAsString();
113 if (!Val.empty())
114 Rec.Operands.push_back({getOrEmitString(Val, MAI)});
115 } else {
116 Rec.Operands.push_back(
117 {getOrEmitString(StringPool.save(A.getAsString()), MAI)});
118 }
119 PendingRecords.push_back(std::move(Rec));
120 }
121}
122
123void SPIRVAuxDataHandler::collectMetadataFor(const GlobalObject *GO,
124 ArrayRef<StringRef> MDNames,
127 GO->getAllMetadata(AllMD);
128 if (AllMD.empty())
129 return;
130 AuxDataOpcode Opcode =
132 // MDString operands become OpStrings; ValueAsMetadata constants (e.g.
133 // !{i32 5}) become OpConstants emitted at section 10. Any other operand
134 // kind would need full value translation, so skip the whole node.
135 auto CollectOperands =
136 [&](MDNode *MD) -> std::optional<SmallVector<Operand, 4>> {
137 SmallVector<Operand, 4> Out;
138 for (const MDOperand &MdOp : MD->operands()) {
139 Metadata *Md = MdOp.get();
140 if (auto *MDStr = dyn_cast_or_null<MDString>(Md)) {
141 Out.push_back({getOrEmitString(MDStr->getString(), MAI)});
142 } else if (auto *VAM = dyn_cast_or_null<ValueAsMetadata>(Md)) {
143 auto *C = dyn_cast<Constant>(VAM->getValue());
144 if (!C || !(isa<ConstantInt>(C) || isa<ConstantFP>(C)))
145 return std::nullopt;
146 Out.push_back({MCRegister(), C});
147 } else {
148 return std::nullopt;
149 }
150 }
151 return Out;
152 };
153 for (const auto &MD : AllMD) {
154 if (MD.first == LLVMContext::MD_dbg)
155 continue;
156 StringRef MDName = MDNames[MD.first];
157 if (MDName == "spirv.Decorations" || MDName == "spirv.ParameterDecorations")
158 continue;
159 auto Operands = CollectOperands(MD.second);
160 if (!Operands)
161 continue;
162 ExtInstRecord Rec;
163 Rec.Opcode = Opcode;
164 Rec.Target = GO;
165 Rec.Operands.push_back({getOrEmitString(MDName, MAI)});
166 Rec.Operands.append(Operands->begin(), Operands->end());
167 PendingRecords.push_back(std::move(Rec));
168 }
169}
170
173 return;
174 if (!MAI.getExtInstSetReg(NonSemanticAuxDataSet).isValid())
175 return;
177 Mod.getContext().getMDKindNames(MDNames);
178 for (const GlobalObject &GO : Mod.global_objects()) {
179 if (GO.isDeclaration())
180 continue;
181 collectAttributesFor(&GO, MAI);
182 collectMetadataFor(&GO, MDNames, MAI);
183 }
184}
185
187 MCRegister ExtSetReg = MAI.getExtInstSetReg(NonSemanticAuxDataSet);
188 if (!ExtSetReg.isValid())
189 return;
190
191 MCRegister VoidTypeReg = findOrEmitOpTypeVoid(MAI);
192
193 for (const ExtInstRecord &Rec : PendingRecords) {
194 MCRegister TargetReg = MAI.getGlobalObjReg(Rec.Target);
195 if (!TargetReg.isValid())
196 continue;
198 Operands.push_back(TargetReg);
199 for (const Operand &Op : Rec.Operands)
200 Operands.push_back(Op.Const ? emitConstant(Op.Const, MAI) : Op.Reg);
201 emitAuxDataExtInst(Rec.Opcode, VoidTypeReg, ExtSetReg, Operands, MAI);
202 }
203
204 if (LinkagePreservedGOs.empty())
205 return;
206
207 MCRegister UInt32TypeReg = findOrEmitOpTypeUInt32(MAI);
208 MCRegister AEConstReg;
209 for (const GlobalObject *GO : LinkagePreservedGOs) {
210 MCRegister TargetReg = MAI.getGlobalObjReg(GO);
211 if (!TargetReg.isValid())
212 continue;
213 if (!AEConstReg.isValid())
214 AEConstReg =
215 emitOpConstantUInt32(AvailableExternally, UInt32TypeReg, MAI);
216 emitAuxDataExtInst(LinkageOpcode, VoidTypeReg, ExtSetReg,
217 {TargetReg, AEConstReg}, MAI);
218 }
219}
220
221void SPIRVAuxDataHandler::emitAuxDataExtInst(AuxDataOpcode Opcode,
222 MCRegister VoidTypeReg,
223 MCRegister ExtSetReg,
224 ArrayRef<MCRegister> Operands,
226 MCInst Inst;
227 Inst.setOpcode(SPIRV::OpExtInst);
229 Inst.addOperand(MCOperand::createReg(VoidTypeReg));
230 Inst.addOperand(MCOperand::createReg(ExtSetReg));
231 Inst.addOperand(MCOperand::createImm(Opcode));
232 for (MCRegister R : Operands)
234 emitMCInst(Inst);
235}
236
237void SPIRVAuxDataHandler::emitMCInst(MCInst &Inst) {
238 Asm.OutStreamer->emitInstruction(Inst, Asm.getSubtargetInfo());
239}
240
242SPIRVAuxDataHandler::findOrEmitOpTypeVoid(SPIRV::ModuleAnalysisInfo &MAI) {
243 for (const MachineInstr *MI : MAI.getMSInstrs(SPIRV::MB_TypeConstVars))
244 if (MI->getOpcode() == SPIRV::OpTypeVoid)
245 return MAI.getRegisterAlias(MI->getMF(), MI->getOperand(0).getReg());
246 MCRegister Reg = MAI.getNextIDRegister();
247 MCInst Inst;
248 Inst.setOpcode(SPIRV::OpTypeVoid);
250 emitMCInst(Inst);
251 return Reg;
252}
253
255SPIRVAuxDataHandler::findOrEmitOpTypeInt(unsigned BitWidth,
257 // SPIR-V OpTypeInt: <width>, <signedness>. Signedness 0 = unsigned, 1 =
258 // signed; we always emit unsigned.
259 constexpr int64_t UnsignedSignedness = 0;
260 for (const MachineInstr *MI : MAI.getMSInstrs(SPIRV::MB_TypeConstVars))
261 if (MI->getOpcode() == SPIRV::OpTypeInt &&
262 MI->getOperand(1).getImm() == static_cast<int64_t>(BitWidth) &&
263 MI->getOperand(2).getImm() == UnsignedSignedness)
264 return MAI.getRegisterAlias(MI->getMF(), MI->getOperand(0).getReg());
265 MCRegister Reg = MAI.getNextIDRegister();
266 MCInst Inst;
267 Inst.setOpcode(SPIRV::OpTypeInt);
270 Inst.addOperand(MCOperand::createImm(UnsignedSignedness));
271 emitMCInst(Inst);
272 return Reg;
273}
274
276SPIRVAuxDataHandler::findOrEmitOpTypeUInt32(SPIRV::ModuleAnalysisInfo &MAI) {
277 return findOrEmitOpTypeInt(32, MAI);
278}
279
281SPIRVAuxDataHandler::findOrEmitOpTypeFloat(unsigned BitWidth,
283 for (const MachineInstr *MI : MAI.getMSInstrs(SPIRV::MB_TypeConstVars))
284 if (MI->getOpcode() == SPIRV::OpTypeFloat &&
285 MI->getOperand(1).getImm() == static_cast<int64_t>(BitWidth))
286 return MAI.getRegisterAlias(MI->getMF(), MI->getOperand(0).getReg());
287 MCRegister Reg = MAI.getNextIDRegister();
288 MCInst Inst;
289 Inst.setOpcode(SPIRV::OpTypeFloat);
292 emitMCInst(Inst);
293 return Reg;
294}
295
296MCRegister SPIRVAuxDataHandler::emitConstant(const Constant *C,
298 auto [It, Inserted] = ConstantRegs.try_emplace(C);
299 if (!Inserted)
300 return It->second;
301
302 APInt Bits;
303 unsigned Opcode;
304 MCRegister TypeReg;
305 if (const auto *CI = dyn_cast<ConstantInt>(C)) {
306 Bits = CI->getValue();
307 Opcode = SPIRV::OpConstantI;
308 TypeReg = findOrEmitOpTypeInt(Bits.getBitWidth(), MAI);
309 } else {
310 const auto *CF = cast<ConstantFP>(C);
311 Bits = CF->getValueAPF().bitcastToAPInt();
312 Opcode = SPIRV::OpConstantF;
313 TypeReg = findOrEmitOpTypeFloat(Bits.getBitWidth(), MAI);
314 }
315
316 MCRegister Reg = MAI.getNextIDRegister();
317 It->second = Reg;
318 MCInst Inst;
319 Inst.setOpcode(Opcode);
321 Inst.addOperand(MCOperand::createReg(TypeReg));
322 // SPIR-V encodes the literal as ceil(width/32) little-endian 32-bit words.
323 unsigned NumWords = divideCeil(Bits.getBitWidth(), 32);
324 for (unsigned I = 0; I < NumWords; ++I)
325 Inst.addOperand(MCOperand::createImm(Bits.extractBitsAsZExtValue(
326 std::min(32u, Bits.getBitWidth() - I * 32), I * 32)));
327 // The asm printer needs this hint to render an f16 literal correctly.
328 if (Opcode == SPIRV::OpConstantF && Bits.getBitWidth() == 16)
330 emitMCInst(Inst);
331 return Reg;
332}
333
334MCRegister SPIRVAuxDataHandler::emitOpConstantUInt32(
335 uint32_t Value, MCRegister UInt32TypeReg, SPIRV::ModuleAnalysisInfo &MAI) {
336 MCRegister Reg = MAI.getNextIDRegister();
337 MCInst Inst;
338 Inst.setOpcode(SPIRV::OpConstantI);
340 Inst.addOperand(MCOperand::createReg(UInt32TypeReg));
341 Inst.addOperand(MCOperand::createImm(static_cast<int64_t>(Value)));
342 emitMCInst(Inst);
343 return Reg;
344}
This file contains the simple types necessary to represent the attributes associated with functions a...
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)
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::Optional, cl::Hidden, cl::init(false))
static bool wasAvailableExternally(const GlobalObject *GO)
#define SPIRV_WAS_AVAILABLE_EXTERNALLY_ATTR
Definition SPIRVUtils.h:541
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:407
Functions, function parameters, and return types can have attributes to indicate how they should be t...
Definition Attributes.h:105
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:346
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:67
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.
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.
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
@ C
The default llvm calling convention, compatible with C.
Definition CallingConv.h:34
initializer< Ty > init(const Ty &Val)
This is an optimization pass for GlobalISel generic memory operations.
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:394
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
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 getGlobalObjReg(const GlobalObject *GO)
void addExtension(Extension::Extension ToAdd)