1//===- AMDKernelCodeTUtils.cpp --------------------------------------------===//
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//
9/// \file - utility functions to parse/print AMDGPUMCKernelCodeT structure
10//
11//===----------------------------------------------------------------------===//
12
13#include "AMDKernelCodeTUtils.h"
14#include "AMDKernelCodeT.h"
15#include "MCTargetDesc/AMDGPUMCTargetDesc.h"
16#include "SIDefines.h"
17#include "Utils/AMDGPUBaseInfo.h"
18#include "Utils/SIDefinesUtils.h"
19#include "llvm/ADT/StringRef.h"
20#include "llvm/MC/MCContext.h"
21#include "llvm/MC/MCExpr.h"
22#include "llvm/MC/MCParser/AsmLexer.h"
23#include "llvm/MC/MCParser/MCAsmParser.h"
24#include "llvm/MC/MCStreamer.h"
25#include "llvm/MC/MCSubtargetInfo.h"
26#include "llvm/Support/MathExtras.h"
27#include "llvm/Support/raw_ostream.h"
28
29using namespace llvm;
30using namespace llvm::AMDGPU;
31
32// Generates the following for AMDGPUMCKernelCodeT struct members:
33// - HasMemberXXXXX class
34// A check to see if AMDGPUMCKernelCodeT has a specific member so it can
35// determine which of the original amd_kernel_code_t members are duplicated
36// (if the names don't match, the table driven strategy won't work).
37// - IsMCExprXXXXX class
38// Check whether a AMDGPUMCKernelcodeT struct member is MCExpr-ified or not.
39// - GetMemberXXXXX class
40// A retrieval helper for said member (of type const MCExpr *&). Will return
41// a `Phony` const MCExpr * initialized to nullptr to preserve reference
42// returns.
43#define GEN_HAS_MEMBER(member) \
44 class HasMember##member { \
45 template <typename U> \
46 using check_member = decltype(std::declval<U>().member); \
47 \
48 public: \
49 static constexpr bool RESULT = \
50 llvm::is_detected<check_member, AMDGPUMCKernelCodeT>::value; \
51 }; \
52 class IsMCExpr##member { \
53 template <typename U> \
54 static constexpr auto HasMCExprType(int) -> std::bool_constant< \
55 HasMember##member::RESULT && \
56 std::is_same_v<decltype(U::member), const MCExpr *>>; \
57 template <typename U> static constexpr std::false_type HasMCExprType(...); \
58 \
59 public: \
60 static constexpr bool RESULT = \
61 decltype(HasMCExprType<AMDGPUMCKernelCodeT>(0))::value; \
62 }; \
63 class GetMember##member { \
64 public: \
65 static const MCExpr *Phony; \
66 template <typename U> static const MCExpr *&Get(U &C) { \
67 if constexpr (IsMCExpr##member::RESULT) \
68 return C.member; \
69 else \
70 return Phony; \
71 } \
72 }; \
73 const MCExpr *GetMember##member::Phony = nullptr;
74
75// Cannot generate class declarations using the table driver approach (see table
76// in AMDKernelCodeTInfo.h). Luckily, if any are missing here or eventually
77// added to the table, an error should occur when trying to retrieve the table
78// in getMCExprIndexTable.
79GEN_HAS_MEMBER(amd_code_version_major)
80GEN_HAS_MEMBER(amd_code_version_minor)
81GEN_HAS_MEMBER(amd_machine_kind)
82GEN_HAS_MEMBER(amd_machine_version_major)
83GEN_HAS_MEMBER(amd_machine_version_minor)
84GEN_HAS_MEMBER(amd_machine_version_stepping)
85
86GEN_HAS_MEMBER(kernel_code_entry_byte_offset)
87GEN_HAS_MEMBER(kernel_code_prefetch_byte_size)
88
89GEN_HAS_MEMBER(granulated_workitem_vgpr_count)
90GEN_HAS_MEMBER(granulated_wavefront_sgpr_count)
91GEN_HAS_MEMBER(priority)
92GEN_HAS_MEMBER(float_mode)
93GEN_HAS_MEMBER(priv)
94GEN_HAS_MEMBER(enable_dx10_clamp)
95GEN_HAS_MEMBER(debug_mode)
96GEN_HAS_MEMBER(enable_ieee_mode)
97GEN_HAS_MEMBER(enable_wgp_mode)
98GEN_HAS_MEMBER(enable_mem_ordered)
99GEN_HAS_MEMBER(enable_fwd_progress)
100
101GEN_HAS_MEMBER(enable_sgpr_private_segment_wave_byte_offset)
102GEN_HAS_MEMBER(user_sgpr_count)
103GEN_HAS_MEMBER(enable_trap_handler)
104GEN_HAS_MEMBER(enable_sgpr_workgroup_id_x)
105GEN_HAS_MEMBER(enable_sgpr_workgroup_id_y)
106GEN_HAS_MEMBER(enable_sgpr_workgroup_id_z)
107GEN_HAS_MEMBER(enable_sgpr_workgroup_info)
108GEN_HAS_MEMBER(enable_vgpr_workitem_id)
109GEN_HAS_MEMBER(enable_exception_msb)
110GEN_HAS_MEMBER(granulated_lds_size)
111GEN_HAS_MEMBER(enable_exception)
112
113GEN_HAS_MEMBER(enable_sgpr_private_segment_buffer)
114GEN_HAS_MEMBER(enable_sgpr_dispatch_ptr)
115GEN_HAS_MEMBER(enable_sgpr_queue_ptr)
116GEN_HAS_MEMBER(enable_sgpr_kernarg_segment_ptr)
117GEN_HAS_MEMBER(enable_sgpr_dispatch_id)
118GEN_HAS_MEMBER(enable_sgpr_flat_scratch_init)
119GEN_HAS_MEMBER(enable_sgpr_private_segment_size)
120GEN_HAS_MEMBER(enable_sgpr_grid_workgroup_count_x)
121GEN_HAS_MEMBER(enable_sgpr_grid_workgroup_count_y)
122GEN_HAS_MEMBER(enable_sgpr_grid_workgroup_count_z)
123GEN_HAS_MEMBER(enable_wavefront_size32)
124GEN_HAS_MEMBER(enable_ordered_append_gds)
125GEN_HAS_MEMBER(private_element_size)
126GEN_HAS_MEMBER(is_ptr64)
127GEN_HAS_MEMBER(is_dynamic_callstack)
128GEN_HAS_MEMBER(is_debug_enabled)
129GEN_HAS_MEMBER(is_xnack_enabled)
130
131GEN_HAS_MEMBER(workitem_private_segment_byte_size)
132GEN_HAS_MEMBER(workgroup_group_segment_byte_size)
133GEN_HAS_MEMBER(gds_segment_byte_size)
134GEN_HAS_MEMBER(kernarg_segment_byte_size)
135GEN_HAS_MEMBER(workgroup_fbarrier_count)
136GEN_HAS_MEMBER(wavefront_sgpr_count)
137GEN_HAS_MEMBER(workitem_vgpr_count)
138GEN_HAS_MEMBER(reserved_vgpr_first)
139GEN_HAS_MEMBER(reserved_vgpr_count)
140GEN_HAS_MEMBER(reserved_sgpr_first)
141GEN_HAS_MEMBER(reserved_sgpr_count)
142GEN_HAS_MEMBER(debug_wavefront_private_segment_offset_sgpr)
143GEN_HAS_MEMBER(debug_private_segment_buffer_sgpr)
144GEN_HAS_MEMBER(kernarg_segment_alignment)
145GEN_HAS_MEMBER(group_segment_alignment)
146GEN_HAS_MEMBER(private_segment_alignment)
147GEN_HAS_MEMBER(wavefront_size)
148GEN_HAS_MEMBER(call_convention)
149GEN_HAS_MEMBER(runtime_loader_kernel_symbol)
150
151static ArrayRef<StringLiteral> get_amd_kernel_code_t_FldNames() {
152 static constexpr StringLiteral const Table[] = {
153 "", // not found placeholder
154#define RECORD(name, altName, print, parse) #name
155#include "Utils/AMDKernelCodeTInfo.h"
156#undef RECORD
157 };
158 return ArrayRef(Table);
159}
160
161static ArrayRef<StringLiteral> get_amd_kernel_code_t_FldAltNames() {
162 static constexpr StringLiteral const Table[] = {
163 "", // not found placeholder
164#define RECORD(name, altName, print, parse) #altName
165#include "Utils/AMDKernelCodeTInfo.h"
166#undef RECORD
167 };
168 return ArrayRef(Table);
169}
170
171static ArrayRef<bool> hasMCExprVersionTable() {
172 static bool const Table[] = {
173#define RECORD(name, altName, print, parse) (IsMCExpr##name::RESULT)
174#include "Utils/AMDKernelCodeTInfo.h"
175#undef RECORD
176 };
177 return ArrayRef(Table);
178}
179
180using RetrieveFx = const MCExpr *&(*)(AMDGPUMCKernelCodeT &);
181
182static ArrayRef<RetrieveFx> getMCExprIndexTable() {
183 static const RetrieveFx Table[] = {
184#define RECORD(name, altName, print, parse) GetMember##name::Get
185#include "Utils/AMDKernelCodeTInfo.h"
186#undef RECORD
187 };
188 return ArrayRef(Table);
189}
190
191static StringMap<int> createIndexMap(ArrayRef<StringLiteral> names,
192 ArrayRef<StringLiteral> altNames) {
193 StringMap<int> map;
194 assert(names.size() == altNames.size());
195 for (unsigned i = 0; i < names.size(); ++i) {
196 map.insert(KV: std::pair(names[i], i));
197 map.insert(KV: std::pair(altNames[i], i));
198 }
199 return map;
200}
201
202static int get_amd_kernel_code_t_FieldIndex(StringRef name) {
203 static const auto map = createIndexMap(names: get_amd_kernel_code_t_FldNames(),
204 altNames: get_amd_kernel_code_t_FldAltNames());
205 return map.lookup(Key: name) - 1; // returns -1 if not found
206}
207
208class PrintField {
209public:
210 template <typename T, T AMDGPUMCKernelCodeT::*ptr>
211 static void printField(StringRef Name, const AMDGPUMCKernelCodeT &C,
212 raw_ostream &OS, MCContext &Ctx,
213 AMDGPUMCKernelCodeT::PrintHelper Helper) {
214 if constexpr (!std::is_integral_v<T>) {
215 OS << Name << " = ";
216 const MCExpr *Value = C.*ptr;
217 Helper(Value, OS, Ctx.getAsmInfo());
218 } else {
219 OS << Name << " = " << (int)(C.*ptr);
220 }
221 }
222};
223
224template <typename T, T AMDGPUMCKernelCodeT::*ptr, int shift, int width = 1>
225static void printBitField(StringRef Name, const AMDGPUMCKernelCodeT &C,
226 raw_ostream &OS, MCContext &,
227 AMDGPUMCKernelCodeT::PrintHelper) {
228 const auto Mask = (static_cast<T>(1) << width) - 1;
229 OS << Name << " = " << (int)((C.*ptr >> shift) & Mask);
230}
231
232using PrintFx = void (*)(StringRef, const AMDGPUMCKernelCodeT &, raw_ostream &,
233 MCContext &, AMDGPUMCKernelCodeT::PrintHelper Helper);
234
235static ArrayRef<PrintFx>
236getPrinterTable(AMDGPUMCKernelCodeT::PrintHelper Helper) {
237 static const PrintFx Table[] = {
238#define COMPPGM1(name, aname, AccMacro) \
239 COMPPGM(name, aname, C_00B848_##AccMacro, S_00B848_##AccMacro, 0)
240#define COMPPGM2(name, aname, AccMacro) \
241 COMPPGM(name, aname, C_00B84C_##AccMacro, S_00B84C_##AccMacro, 32)
242#define PRINTFIELD(sname, aname, name) PrintField::printField<FLD_T(name)>
243#define PRINTCOMP(Complement, PGMType) \
244 [](StringRef Name, const AMDGPUMCKernelCodeT &C, raw_ostream &OS, \
245 MCContext &Ctx, AMDGPUMCKernelCodeT::PrintHelper Helper) { \
246 OS << Name << " = "; \
247 auto [Shift, Mask] = getShiftMask(Complement); \
248 const MCExpr *Value; \
249 if (PGMType == 0) { \
250 Value = \
251 maskShiftGet(C.compute_pgm_resource1_registers, Mask, Shift, Ctx); \
252 } else { \
253 Value = \
254 maskShiftGet(C.compute_pgm_resource2_registers, Mask, Shift, Ctx); \
255 } \
256 Helper(Value, OS, Ctx.getAsmInfo()); \
257 }
258#define RECORD(name, altName, print, parse) print
259#include "Utils/AMDKernelCodeTInfo.h"
260#undef RECORD
261 };
262 return ArrayRef(Table);
263}
264
265static bool expectAbsExpression(MCAsmParser &MCParser, int64_t &Value,
266 raw_ostream &Err) {
267
268 if (MCParser.getLexer().isNot(K: AsmToken::Equal)) {
269 Err << "expected '='";
270 return false;
271 }
272 MCParser.getLexer().Lex();
273
274 if (MCParser.parseAbsoluteExpression(Res&: Value)) {
275 Err << "integer absolute expression expected";
276 return false;
277 }
278 return true;
279}
280
281template <typename T, T AMDGPUMCKernelCodeT::*ptr>
282static bool parseField(AMDGPUMCKernelCodeT &C, MCAsmParser &MCParser,
283 raw_ostream &Err) {
284 int64_t Value = 0;
285 if (!expectAbsExpression(MCParser, Value, Err))
286 return false;
287 C.*ptr = (T)Value;
288 return true;
289}
290
291template <typename T, T AMDGPUMCKernelCodeT::*ptr, int shift, int width = 1>
292static bool parseBitField(AMDGPUMCKernelCodeT &C, MCAsmParser &MCParser,
293 raw_ostream &Err) {
294 int64_t Value = 0;
295 if (!expectAbsExpression(MCParser, Value, Err))
296 return false;
297 const uint64_t Mask = ((UINT64_C(1) << width) - 1) << shift;
298 C.*ptr &= (T)~Mask;
299 C.*ptr |= (T)((Value << shift) & Mask);
300 return true;
301}
302
303static bool parseExpr(MCAsmParser &MCParser, const MCExpr *&Value,
304 raw_ostream &Err) {
305 if (MCParser.getLexer().isNot(K: AsmToken::Equal)) {
306 Err << "expected '='";
307 return false;
308 }
309 MCParser.getLexer().Lex();
310
311 if (MCParser.parseExpression(Res&: Value)) {
312 Err << "Could not parse expression";
313 return false;
314 }
315 return true;
316}
317
318using ParseFx = bool (*)(AMDGPUMCKernelCodeT &, MCAsmParser &, raw_ostream &);
319
320static ArrayRef<ParseFx> getParserTable() {
321 static const ParseFx Table[] = {
322#define COMPPGM1(name, aname, AccMacro) \
323 COMPPGM(name, aname, G_00B848_##AccMacro, C_00B848_##AccMacro, 0)
324#define COMPPGM2(name, aname, AccMacro) \
325 COMPPGM(name, aname, G_00B84C_##AccMacro, C_00B84C_##AccMacro, 32)
326#define PARSECOMP(Complement, PGMType) \
327 [](AMDGPUMCKernelCodeT &C, MCAsmParser &MCParser, \
328 raw_ostream &Err) -> bool { \
329 MCContext &Ctx = MCParser.getContext(); \
330 const MCExpr *Value; \
331 if (!parseExpr(MCParser, Value, Err)) \
332 return false; \
333 auto [Shift, Mask] = getShiftMask(Complement); \
334 Value = maskShiftSet(Value, Mask, Shift, Ctx); \
335 const MCExpr *Compl = MCConstantExpr::create(Complement, Ctx); \
336 if (PGMType == 0) { \
337 C.compute_pgm_resource1_registers = MCBinaryExpr::createAnd( \
338 C.compute_pgm_resource1_registers, Compl, Ctx); \
339 C.compute_pgm_resource1_registers = MCBinaryExpr::createOr( \
340 C.compute_pgm_resource1_registers, Value, Ctx); \
341 } else { \
342 C.compute_pgm_resource2_registers = MCBinaryExpr::createAnd( \
343 C.compute_pgm_resource2_registers, Compl, Ctx); \
344 C.compute_pgm_resource2_registers = MCBinaryExpr::createOr( \
345 C.compute_pgm_resource2_registers, Value, Ctx); \
346 } \
347 return true; \
348 }
349#define RECORD(name, altName, print, parse) parse
350#include "Utils/AMDKernelCodeTInfo.h"
351#undef RECORD
352 };
353 return ArrayRef(Table);
354}
355
356static void printAmdKernelCodeField(const AMDGPUMCKernelCodeT &C, int FldIndex,
357 raw_ostream &OS, MCContext &Ctx,
358 AMDGPUMCKernelCodeT::PrintHelper Helper) {
359 auto Printer = getPrinterTable(Helper)[FldIndex];
360 if (Printer)
361 Printer(get_amd_kernel_code_t_FldNames()[FldIndex + 1], C, OS, Ctx, Helper);
362}
363
364void AMDGPUMCKernelCodeT::initDefault(const MCSubtargetInfo *STI,
365 MCContext &Ctx, bool InitMCExpr) {
366 AMDGPUMCKernelCodeT();
367
368 AMDGPU::initDefaultAMDKernelCodeT(Header&: *this, STI);
369
370 if (InitMCExpr) {
371 const MCExpr *ZeroExpr = MCConstantExpr::create(Value: 0, Ctx);
372 compute_pgm_resource1_registers =
373 MCConstantExpr::create(Value: Lo_32(Value: compute_pgm_resource_registers), Ctx);
374 compute_pgm_resource2_registers =
375 MCConstantExpr::create(Value: Hi_32(Value: compute_pgm_resource_registers), Ctx);
376 is_dynamic_callstack = ZeroExpr;
377 wavefront_sgpr_count = ZeroExpr;
378 workitem_vgpr_count = ZeroExpr;
379 workitem_private_segment_byte_size = ZeroExpr;
380 }
381}
382
383void AMDGPUMCKernelCodeT::validate(const MCSubtargetInfo *STI, MCContext &Ctx) {
384 int64_t Value;
385 if (!compute_pgm_resource1_registers->evaluateAsAbsolute(Res&: Value))
386 return;
387
388 if (G_00B848_DX10_CLAMP(Value) &&
389 !STI->hasFeature(Feature: AMDGPU::FeatureDX10ClampAndIEEEMode)) {
390 Ctx.reportError(L: {}, Msg: "enable_dx10_clamp=1 is not allowed on GFX1170+");
391 return;
392 }
393
394 if (G_00B848_IEEE_MODE(Value) &&
395 !STI->hasFeature(Feature: AMDGPU::FeatureDX10ClampAndIEEEMode)) {
396 Ctx.reportError(L: {}, Msg: "enable_ieee_mode=1 is not allowed on GFX1170+");
397 return;
398 }
399
400 if (G_00B848_WGP_MODE(Value) && !AMDGPU::isGFX10Plus(STI: *STI)) {
401 Ctx.reportError(L: {}, Msg: "enable_wgp_mode=1 is only allowed on GFX10+");
402 return;
403 }
404
405 if (G_00B848_MEM_ORDERED(Value) && !AMDGPU::isGFX10Plus(STI: *STI)) {
406 Ctx.reportError(L: {}, Msg: "enable_mem_ordered=1 is only allowed on GFX10+");
407 return;
408 }
409
410 if (G_00B848_FWD_PROGRESS(Value) && !AMDGPU::isGFX10Plus(STI: *STI)) {
411 Ctx.reportError(L: {}, Msg: "enable_fwd_progress=1 is only allowed on GFX10+");
412 return;
413 }
414}
415
416const MCExpr *&AMDGPUMCKernelCodeT::getMCExprForIndex(int Index) {
417 static const auto IndexTable = getMCExprIndexTable();
418 return IndexTable[Index](*this);
419}
420
421bool AMDGPUMCKernelCodeT::ParseKernelCodeT(StringRef ID, MCAsmParser &MCParser,
422 raw_ostream &Err) {
423 const int Idx = get_amd_kernel_code_t_FieldIndex(name: ID);
424 if (Idx < 0) {
425 Err << "unexpected amd_kernel_code_t field name " << ID;
426 return false;
427 }
428
429 if (hasMCExprVersionTable()[Idx]) {
430 const MCExpr *Value;
431 if (!parseExpr(MCParser, Value, Err))
432 return false;
433 getMCExprForIndex(Index: Idx) = Value;
434 return true;
435 }
436 auto Parser = getParserTable()[Idx];
437 return Parser && Parser(*this, MCParser, Err);
438}
439
440void AMDGPUMCKernelCodeT::EmitKernelCodeT(raw_ostream &OS, MCContext &Ctx,
441 PrintHelper Helper) {
442 const int Size = hasMCExprVersionTable().size();
443 for (int i = 0; i < Size; ++i) {
444 OS << "\t\t";
445 if (hasMCExprVersionTable()[i]) {
446 OS << get_amd_kernel_code_t_FldNames()[i + 1] << " = ";
447 const MCExpr *Value = getMCExprForIndex(Index: i);
448 Helper(Value, OS, Ctx.getAsmInfo());
449 } else {
450 printAmdKernelCodeField(C: *this, FldIndex: i, OS, Ctx, Helper);
451 }
452 OS << '\n';
453 }
454}
455
456void AMDGPUMCKernelCodeT::EmitKernelCodeT(MCStreamer &OS, MCContext &Ctx) {
457 OS.emitIntValue(Value: amd_kernel_code_version_major, /*Size=*/4);
458 OS.emitIntValue(Value: amd_kernel_code_version_minor, /*Size=*/4);
459 OS.emitIntValue(Value: amd_machine_kind, /*Size=*/2);
460 OS.emitIntValue(Value: amd_machine_version_major, /*Size=*/2);
461 OS.emitIntValue(Value: amd_machine_version_minor, /*Size=*/2);
462 OS.emitIntValue(Value: amd_machine_version_stepping, /*Size=*/2);
463 OS.emitIntValue(Value: kernel_code_entry_byte_offset, /*Size=*/8);
464 OS.emitIntValue(Value: kernel_code_prefetch_byte_offset, /*Size=*/8);
465 OS.emitIntValue(Value: kernel_code_prefetch_byte_size, /*Size=*/8);
466 OS.emitIntValue(Value: reserved0, /*Size=*/8);
467
468 if (compute_pgm_resource1_registers != nullptr)
469 OS.emitValue(Value: compute_pgm_resource1_registers, /*Size=*/4);
470 else
471 OS.emitIntValue(Value: Lo_32(Value: compute_pgm_resource_registers),
472 /*Size=*/4);
473
474 if (compute_pgm_resource2_registers != nullptr)
475 OS.emitValue(Value: compute_pgm_resource2_registers, /*Size=*/4);
476 else
477 OS.emitIntValue(Value: Hi_32(Value: compute_pgm_resource_registers),
478 /*Size=*/4);
479
480 if (is_dynamic_callstack != nullptr) {
481 const MCExpr *CodeProps = MCConstantExpr::create(Value: code_properties, Ctx);
482 CodeProps = MCBinaryExpr::createOr(
483 LHS: CodeProps,
484 RHS: maskShiftSet(Val: is_dynamic_callstack,
485 Mask: (1 << AMD_CODE_PROPERTY_IS_DYNAMIC_CALLSTACK_WIDTH) - 1,
486 Shift: AMD_CODE_PROPERTY_IS_DYNAMIC_CALLSTACK_SHIFT, Ctx),
487 Ctx);
488 OS.emitValue(Value: CodeProps, /*Size=*/4);
489 } else
490 OS.emitIntValue(Value: code_properties, /*Size=*/4);
491
492 if (workitem_private_segment_byte_size != nullptr)
493 OS.emitValue(Value: workitem_private_segment_byte_size, /*Size=*/4);
494 else
495 OS.emitIntValue(Value: 0, /*Size=*/4);
496
497 OS.emitIntValue(Value: workgroup_group_segment_byte_size, /*Size=*/4);
498 OS.emitIntValue(Value: gds_segment_byte_size, /*Size=*/4);
499 OS.emitIntValue(Value: kernarg_segment_byte_size, /*Size=*/8);
500 OS.emitIntValue(Value: workgroup_fbarrier_count, /*Size=*/4);
501
502 if (wavefront_sgpr_count != nullptr)
503 OS.emitValue(Value: wavefront_sgpr_count, /*Size=*/2);
504 else
505 OS.emitIntValue(Value: 0, /*Size=*/2);
506
507 if (workitem_vgpr_count != nullptr)
508 OS.emitValue(Value: workitem_vgpr_count, /*Size=*/2);
509 else
510 OS.emitIntValue(Value: 0, /*Size=*/2);
511
512 OS.emitIntValue(Value: reserved_vgpr_first, /*Size=*/2);
513 OS.emitIntValue(Value: reserved_vgpr_count, /*Size=*/2);
514 OS.emitIntValue(Value: reserved_sgpr_first, /*Size=*/2);
515 OS.emitIntValue(Value: reserved_sgpr_count, /*Size=*/2);
516 OS.emitIntValue(Value: debug_wavefront_private_segment_offset_sgpr,
517 /*Size=*/2);
518 OS.emitIntValue(Value: debug_private_segment_buffer_sgpr, /*Size=*/2);
519 OS.emitIntValue(Value: kernarg_segment_alignment, /*Size=*/1);
520 OS.emitIntValue(Value: group_segment_alignment, /*Size=*/1);
521 OS.emitIntValue(Value: private_segment_alignment, /*Size=*/1);
522 OS.emitIntValue(Value: wavefront_size, /*Size=*/1);
523
524 OS.emitIntValue(Value: call_convention, /*Size=*/4);
525 OS.emitBytes(Data: StringRef((const char *)reserved3, /*Size=*/12));
526 OS.emitIntValue(Value: runtime_loader_kernel_symbol, /*Size=*/8);
527 OS.emitBytes(Data: StringRef((const char *)control_directives, /*Size=*/16 * 8));
528}
529