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