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"
26
27using namespace llvm;
28
30 "spirv-preserve-auxdata",
31 cl::desc("Preserve LLVM attributes and metadata as "
32 "NonSemantic.AuxData ExtInst annotations (requires "
33 "SPV_KHR_non_semantic_info)"),
35
36namespace {
37enum AuxDataLinkageType : uint32_t {
38 AvailableExternally = 0,
39};
40
41constexpr unsigned NonSemanticAuxDataSet =
42 static_cast<unsigned>(SPIRV::InstructionSet::NonSemantic_AuxData);
43
44AttributeSet getGOAttrs(const GlobalObject *GO) {
45 if (const auto *F = dyn_cast<Function>(GO))
46 return F->getAttributes().getFnAttrs();
47 return cast<GlobalVariable>(GO)->getAttributes();
48}
49} // namespace
50
51static bool wasAvailableExternally(const GlobalObject *GO) {
52 if (const auto *F = dyn_cast<Function>(GO))
53 return F->hasFnAttribute(SPIRV_WAS_AVAILABLE_EXTERNALLY_ATTR);
54 return cast<GlobalVariable>(GO)->getAttributes().hasAttribute(
56}
57
59 : Asm(AP), Mod(M) {
60 for (const GlobalObject &GO : M.global_objects())
62 LinkagePreservedGOs.push_back(&GO);
63}
64
66
69 if (!hasWork())
70 return;
71 if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_non_semantic_info)) {
73 report_fatal_error("-spirv-preserve-auxdata requires the "
74 "SPV_KHR_non_semantic_info extension to be enabled.");
75 return;
76 }
77 MAI.Reqs.addExtension(SPIRV::Extension::SPV_KHR_non_semantic_info);
78 if (!MAI.ExtInstSetMap.count(NonSemanticAuxDataSet))
79 MAI.ExtInstSetMap[NonSemanticAuxDataSet] = MAI.getNextIDRegister();
80}
81
83SPIRVAuxDataHandler::getOrEmitString(StringRef S,
85 auto [It, Inserted] = StringRegs.try_emplace(S);
86 if (!Inserted)
87 return It->second;
88 MCRegister Reg = MAI.getNextIDRegister();
89 It->second = Reg;
90 MCInst Inst;
91 Inst.setOpcode(SPIRV::OpString);
93 addStringImm(S, Inst);
94 emitMCInst(Inst);
95 return Reg;
96}
97
98void SPIRVAuxDataHandler::collectAttributesFor(const GlobalObject *GO,
102 for (const Attribute &A : getGOAttrs(GO)) {
103 if (A.isStringAttribute() &&
104 A.getKindAsString() == SPIRV_WAS_AVAILABLE_EXTERNALLY_ATTR)
105 continue;
106 ExtInstRecord Rec;
107 Rec.Opcode = Opcode;
108 Rec.Target = GO;
109 if (A.isStringAttribute()) {
110 Rec.Operands.push_back({getOrEmitString(A.getKindAsString(), MAI)});
111 StringRef Val = A.getValueAsString();
112 if (!Val.empty())
113 Rec.Operands.push_back({getOrEmitString(Val, MAI)});
114 } else {
115 Rec.Operands.push_back(
116 {getOrEmitString(StringPool.save(A.getAsString()), MAI)});
117 }
118 PendingRecords.push_back(std::move(Rec));
119 }
120}
121
122void SPIRVAuxDataHandler::collectMetadataFor(const GlobalObject *GO,
123 ArrayRef<StringRef> MDNames,
126 GO->getAllMetadata(AllMD);
127 if (AllMD.empty())
128 return;
129 AuxDataOpcode Opcode =
131 // MDString operands become OpStrings; ValueAsMetadata constants (e.g.
132 // !{i32 5}) become OpConstants emitted at section 10. Any other operand
133 // kind would need full value translation, so skip the whole node.
134 auto CollectOperands =
135 [&](MDNode *MD) -> std::optional<SmallVector<Operand, 4>> {
136 SmallVector<Operand, 4> Out;
137 for (const MDOperand &MdOp : MD->operands()) {
138 Metadata *Md = MdOp.get();
139 if (auto *MDStr = dyn_cast_or_null<MDString>(Md)) {
140 Out.push_back({getOrEmitString(MDStr->getString(), MAI)});
141 } else if (auto *VAM = dyn_cast_or_null<ValueAsMetadata>(Md)) {
142 auto *C = dyn_cast<Constant>(VAM->getValue());
143 if (!C || !(isa<ConstantInt>(C) || isa<ConstantFP>(C)))
144 return std::nullopt;
145 Out.push_back({MCRegister(), C});
146 } else {
147 return std::nullopt;
148 }
149 }
150 return Out;
151 };
152 for (const auto &MD : AllMD) {
153 if (MD.first == LLVMContext::MD_dbg)
154 continue;
155 StringRef MDName = MDNames[MD.first];
156 if (MDName == "spirv.Decorations" || MDName == "spirv.ParameterDecorations")
157 continue;
158 auto Operands = CollectOperands(MD.second);
159 if (!Operands)
160 continue;
161 ExtInstRecord Rec;
162 Rec.Opcode = Opcode;
163 Rec.Target = GO;
164 Rec.Operands.push_back({getOrEmitString(MDName, MAI)});
165 Rec.Operands.append(Operands->begin(), Operands->end());
166 PendingRecords.push_back(std::move(Rec));
167 }
168}
169
172 return;
173 if (!MAI.getExtInstSetReg(NonSemanticAuxDataSet).isValid())
174 return;
176 Mod.getContext().getMDKindNames(MDNames);
177 for (const GlobalObject &GO : Mod.global_objects()) {
178 if (GO.isDeclaration())
179 continue;
180 collectAttributesFor(&GO, MAI);
181 collectMetadataFor(&GO, MDNames, MAI);
182 }
183}
184
186 MCRegister ExtSetReg = MAI.getExtInstSetReg(NonSemanticAuxDataSet);
187 if (!ExtSetReg.isValid())
188 return;
189
190 MCRegister VoidTypeReg = findOrEmitOpTypeVoid(MAI);
191
192 for (const ExtInstRecord &Rec : PendingRecords) {
193 MCRegister TargetReg = MAI.getGlobalObjReg(Rec.Target);
194 if (!TargetReg.isValid())
195 continue;
197 Operands.push_back(TargetReg);
198 for (const Operand &Op : Rec.Operands)
199 Operands.push_back(Op.Const ? emitConstant(Op.Const, MAI) : Op.Reg);
200 emitAuxDataExtInst(Rec.Opcode, VoidTypeReg, ExtSetReg, Operands, MAI);
201 }
202
203 if (LinkagePreservedGOs.empty())
204 return;
205
206 MCRegister UInt32TypeReg = findOrEmitOpTypeUInt32(MAI);
207 MCRegister AEConstReg;
208 for (const GlobalObject *GO : LinkagePreservedGOs) {
209 MCRegister TargetReg = MAI.getGlobalObjReg(GO);
210 if (!TargetReg.isValid())
211 continue;
212 if (!AEConstReg.isValid())
213 AEConstReg =
214 emitOpConstantUInt32(AvailableExternally, UInt32TypeReg, MAI);
215 emitAuxDataExtInst(LinkageOpcode, VoidTypeReg, ExtSetReg,
216 {TargetReg, AEConstReg}, MAI);
217 }
218}
219
220void SPIRVAuxDataHandler::emitAuxDataExtInst(AuxDataOpcode Opcode,
221 MCRegister VoidTypeReg,
222 MCRegister ExtSetReg,
223 ArrayRef<MCRegister> Operands,
225 MCInst Inst;
226 Inst.setOpcode(SPIRV::OpExtInst);
228 Inst.addOperand(MCOperand::createReg(VoidTypeReg));
229 Inst.addOperand(MCOperand::createReg(ExtSetReg));
230 Inst.addOperand(MCOperand::createImm(Opcode));
231 for (MCRegister R : Operands)
233 emitMCInst(Inst);
234}
235
236void SPIRVAuxDataHandler::emitMCInst(MCInst &Inst) {
237 Asm.OutStreamer->emitInstruction(Inst, Asm.getSubtargetInfo());
238}
239
241SPIRVAuxDataHandler::findOrEmitOpTypeVoid(SPIRV::ModuleAnalysisInfo &MAI) {
242 for (const MachineInstr *MI : MAI.getMSInstrs(SPIRV::MB_TypeConstVars))
243 if (MI->getOpcode() == SPIRV::OpTypeVoid)
244 return MAI.getRegisterAlias(MI->getMF(), MI->getOperand(0).getReg());
245 MCRegister Reg = MAI.getNextIDRegister();
246 MCInst Inst;
247 Inst.setOpcode(SPIRV::OpTypeVoid);
249 emitMCInst(Inst);
250 return Reg;
251}
252
254SPIRVAuxDataHandler::findOrEmitOpTypeInt(unsigned BitWidth,
256 // SPIR-V OpTypeInt: <width>, <signedness>. Signedness 0 = unsigned, 1 =
257 // signed; we always emit unsigned.
258 constexpr int64_t UnsignedSignedness = 0;
259 for (const MachineInstr *MI : MAI.getMSInstrs(SPIRV::MB_TypeConstVars))
260 if (MI->getOpcode() == SPIRV::OpTypeInt &&
261 MI->getOperand(1).getImm() == static_cast<int64_t>(BitWidth) &&
262 MI->getOperand(2).getImm() == UnsignedSignedness)
263 return MAI.getRegisterAlias(MI->getMF(), MI->getOperand(0).getReg());
264 MCRegister Reg = MAI.getNextIDRegister();
265 MCInst Inst;
266 Inst.setOpcode(SPIRV::OpTypeInt);
269 Inst.addOperand(MCOperand::createImm(UnsignedSignedness));
270 emitMCInst(Inst);
271 return Reg;
272}
273
275SPIRVAuxDataHandler::findOrEmitOpTypeUInt32(SPIRV::ModuleAnalysisInfo &MAI) {
276 return findOrEmitOpTypeInt(32, MAI);
277}
278
280SPIRVAuxDataHandler::findOrEmitOpTypeFloat(unsigned BitWidth,
282 for (const MachineInstr *MI : MAI.getMSInstrs(SPIRV::MB_TypeConstVars))
283 if (MI->getOpcode() == SPIRV::OpTypeFloat &&
284 MI->getOperand(1).getImm() == static_cast<int64_t>(BitWidth))
285 return MAI.getRegisterAlias(MI->getMF(), MI->getOperand(0).getReg());
286 MCRegister Reg = MAI.getNextIDRegister();
287 MCInst Inst;
288 Inst.setOpcode(SPIRV::OpTypeFloat);
291 emitMCInst(Inst);
292 return Reg;
293}
294
295MCRegister SPIRVAuxDataHandler::emitConstant(const Constant *C,
297 auto [It, Inserted] = ConstantRegs.try_emplace(C);
298 if (!Inserted)
299 return It->second;
300
301 APInt Bits;
302 unsigned Opcode;
303 MCRegister TypeReg;
304 if (const auto *CI = dyn_cast<ConstantInt>(C)) {
305 Bits = CI->getValue();
306 Opcode = SPIRV::OpConstantI;
307 TypeReg = findOrEmitOpTypeInt(Bits.getBitWidth(), MAI);
308 } else {
309 const auto *CF = cast<ConstantFP>(C);
310 Bits = CF->getValueAPF().bitcastToAPInt();
311 Opcode = SPIRV::OpConstantF;
312 TypeReg = findOrEmitOpTypeFloat(Bits.getBitWidth(), MAI);
313 }
314
315 MCRegister Reg = MAI.getNextIDRegister();
316 It->second = Reg;
317 MCInst Inst;
318 Inst.setOpcode(Opcode);
320 Inst.addOperand(MCOperand::createReg(TypeReg));
321 // SPIR-V encodes the literal as ceil(width/32) little-endian 32-bit words.
322 unsigned NumWords = std::max(1u, (Bits.getBitWidth() + 31) / 32);
323 for (unsigned I = 0; I < NumWords; ++I)
324 Inst.addOperand(MCOperand::createImm(Bits.extractBitsAsZExtValue(
325 std::min(32u, Bits.getBitWidth() - I * 32), I * 32)));
326 // The asm printer needs this hint to render an f16 literal correctly.
327 if (Opcode == SPIRV::OpConstantF && Bits.getBitWidth() == 16)
329 emitMCInst(Inst);
330 return Reg;
331}
332
333MCRegister SPIRVAuxDataHandler::emitOpConstantUInt32(
334 uint32_t Value, MCRegister UInt32TypeReg, SPIRV::ModuleAnalysisInfo &MAI) {
335 MCRegister Reg = MAI.getNextIDRegister();
336 MCInst Inst;
337 Inst.setOpcode(SPIRV::OpConstantI);
339 Inst.addOperand(MCOperand::createReg(UInt32TypeReg));
340 Inst.addOperand(MCOperand::createImm(static_cast<int64_t>(Value)));
341 emitMCInst(Inst);
342 return Reg;
343}
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:544
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:337
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.
FunctionAddr VTableAddr Value
Definition InstrProf.h:137
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
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
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)