10b57cec5SDimitry Andric //===- AMDKernelCodeTUtils.cpp --------------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
9*0fca6ea1SDimitry Andric /// \file - utility functions to parse/print AMDGPUMCKernelCodeT structure
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric
130b57cec5SDimitry Andric #include "AMDKernelCodeTUtils.h"
14e8d8bef9SDimitry Andric #include "AMDKernelCodeT.h"
150b57cec5SDimitry Andric #include "SIDefines.h"
16*0fca6ea1SDimitry Andric #include "Utils/AMDGPUBaseInfo.h"
17*0fca6ea1SDimitry Andric #include "Utils/SIDefinesUtils.h"
18*0fca6ea1SDimitry Andric #include "llvm/ADT/IndexedMap.h"
190b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h"
20*0fca6ea1SDimitry Andric #include "llvm/MC/MCContext.h"
21*0fca6ea1SDimitry Andric #include "llvm/MC/MCExpr.h"
220b57cec5SDimitry Andric #include "llvm/MC/MCParser/MCAsmLexer.h"
230b57cec5SDimitry Andric #include "llvm/MC/MCParser/MCAsmParser.h"
24*0fca6ea1SDimitry Andric #include "llvm/MC/MCStreamer.h"
25*0fca6ea1SDimitry Andric #include "llvm/Support/MathExtras.h"
260b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
270b57cec5SDimitry Andric
280b57cec5SDimitry Andric using namespace llvm;
29*0fca6ea1SDimitry Andric using namespace llvm::AMDGPU;
300b57cec5SDimitry Andric
31*0fca6ea1SDimitry Andric // Generates the following for AMDGPUMCKernelCodeT struct members:
32*0fca6ea1SDimitry Andric // - HasMemberXXXXX class
33*0fca6ea1SDimitry Andric // A check to see if AMDGPUMCKernelCodeT has a specific member so it can
34*0fca6ea1SDimitry Andric // determine which of the original amd_kernel_code_t members are duplicated
35*0fca6ea1SDimitry Andric // (if the names don't match, the table driven strategy won't work).
36*0fca6ea1SDimitry Andric // - IsMCExprXXXXX class
37*0fca6ea1SDimitry Andric // Check whether a AMDGPUMCKernelcodeT struct member is MCExpr-ified or not.
38*0fca6ea1SDimitry Andric // - GetMemberXXXXX class
39*0fca6ea1SDimitry Andric // A retrieval helper for said member (of type const MCExpr *&). Will return
40*0fca6ea1SDimitry Andric // a `Phony` const MCExpr * initialized to nullptr to preserve reference
41*0fca6ea1SDimitry Andric // returns.
42*0fca6ea1SDimitry Andric #define GEN_HAS_MEMBER(member) \
43*0fca6ea1SDimitry Andric class HasMember##member { \
44*0fca6ea1SDimitry Andric private: \
45*0fca6ea1SDimitry Andric struct KnownWithMember { \
46*0fca6ea1SDimitry Andric int member; \
47*0fca6ea1SDimitry Andric }; \
48*0fca6ea1SDimitry Andric class AmbiguousDerived : public AMDGPUMCKernelCodeT, \
49*0fca6ea1SDimitry Andric public KnownWithMember {}; \
50*0fca6ea1SDimitry Andric template <typename U> \
51*0fca6ea1SDimitry Andric static constexpr std::false_type Test(decltype(U::member) *); \
52*0fca6ea1SDimitry Andric template <typename U> static constexpr std::true_type Test(...); \
53*0fca6ea1SDimitry Andric \
54*0fca6ea1SDimitry Andric public: \
55*0fca6ea1SDimitry Andric static constexpr bool RESULT = \
56*0fca6ea1SDimitry Andric std::is_same_v<decltype(Test<AmbiguousDerived>(nullptr)), \
57*0fca6ea1SDimitry Andric std::true_type>; \
58*0fca6ea1SDimitry Andric }; \
59*0fca6ea1SDimitry Andric class IsMCExpr##member { \
60*0fca6ea1SDimitry Andric template <typename U, \
61*0fca6ea1SDimitry Andric typename std::enable_if_t< \
62*0fca6ea1SDimitry Andric HasMember##member::RESULT && \
63*0fca6ea1SDimitry Andric std::is_same_v<decltype(U::member), const MCExpr *>, \
64*0fca6ea1SDimitry Andric U> * = nullptr> \
65*0fca6ea1SDimitry Andric static constexpr std::true_type HasMCExprType(decltype(U::member) *); \
66*0fca6ea1SDimitry Andric template <typename U> static constexpr std::false_type HasMCExprType(...); \
67*0fca6ea1SDimitry Andric \
68*0fca6ea1SDimitry Andric public: \
69*0fca6ea1SDimitry Andric static constexpr bool RESULT = \
70*0fca6ea1SDimitry Andric std::is_same_v<decltype(HasMCExprType<AMDGPUMCKernelCodeT>(nullptr)), \
71*0fca6ea1SDimitry Andric std::true_type>; \
72*0fca6ea1SDimitry Andric }; \
73*0fca6ea1SDimitry Andric class GetMember##member { \
74*0fca6ea1SDimitry Andric public: \
75*0fca6ea1SDimitry Andric static const MCExpr *Phony; \
76*0fca6ea1SDimitry Andric template <typename U, typename std::enable_if_t<IsMCExpr##member::RESULT, \
77*0fca6ea1SDimitry Andric U> * = nullptr> \
78*0fca6ea1SDimitry Andric static const MCExpr *&Get(U &C) { \
79*0fca6ea1SDimitry Andric assert(IsMCExpr##member::RESULT && \
80*0fca6ea1SDimitry Andric "Trying to retrieve member that does not exist."); \
81*0fca6ea1SDimitry Andric return C.member; \
82*0fca6ea1SDimitry Andric } \
83*0fca6ea1SDimitry Andric template <typename U, typename std::enable_if_t<!IsMCExpr##member::RESULT, \
84*0fca6ea1SDimitry Andric U> * = nullptr> \
85*0fca6ea1SDimitry Andric static const MCExpr *&Get(U &C) { \
86*0fca6ea1SDimitry Andric return Phony; \
87*0fca6ea1SDimitry Andric } \
88*0fca6ea1SDimitry Andric }; \
89*0fca6ea1SDimitry Andric const MCExpr *GetMember##member::Phony = nullptr;
90*0fca6ea1SDimitry Andric
91*0fca6ea1SDimitry Andric // Cannot generate class declarations using the table driver approach (see table
92*0fca6ea1SDimitry Andric // in AMDKernelCodeTInfo.h). Luckily, if any are missing here or eventually
93*0fca6ea1SDimitry Andric // added to the table, an error should occur when trying to retrieve the table
94*0fca6ea1SDimitry Andric // in getMCExprIndexTable.
95*0fca6ea1SDimitry Andric GEN_HAS_MEMBER(amd_code_version_major)
GEN_HAS_MEMBER(amd_code_version_minor)96*0fca6ea1SDimitry Andric GEN_HAS_MEMBER(amd_code_version_minor)
97*0fca6ea1SDimitry Andric GEN_HAS_MEMBER(amd_machine_kind)
98*0fca6ea1SDimitry Andric GEN_HAS_MEMBER(amd_machine_version_major)
99*0fca6ea1SDimitry Andric GEN_HAS_MEMBER(amd_machine_version_minor)
100*0fca6ea1SDimitry Andric GEN_HAS_MEMBER(amd_machine_version_stepping)
101*0fca6ea1SDimitry Andric
102*0fca6ea1SDimitry Andric GEN_HAS_MEMBER(kernel_code_entry_byte_offset)
103*0fca6ea1SDimitry Andric GEN_HAS_MEMBER(kernel_code_prefetch_byte_size)
104*0fca6ea1SDimitry Andric
105*0fca6ea1SDimitry Andric GEN_HAS_MEMBER(granulated_workitem_vgpr_count)
106*0fca6ea1SDimitry Andric GEN_HAS_MEMBER(granulated_wavefront_sgpr_count)
107*0fca6ea1SDimitry Andric GEN_HAS_MEMBER(priority)
108*0fca6ea1SDimitry Andric GEN_HAS_MEMBER(float_mode)
109*0fca6ea1SDimitry Andric GEN_HAS_MEMBER(priv)
110*0fca6ea1SDimitry Andric GEN_HAS_MEMBER(enable_dx10_clamp)
111*0fca6ea1SDimitry Andric GEN_HAS_MEMBER(debug_mode)
112*0fca6ea1SDimitry Andric GEN_HAS_MEMBER(enable_ieee_mode)
113*0fca6ea1SDimitry Andric GEN_HAS_MEMBER(enable_wgp_mode)
114*0fca6ea1SDimitry Andric GEN_HAS_MEMBER(enable_mem_ordered)
115*0fca6ea1SDimitry Andric GEN_HAS_MEMBER(enable_fwd_progress)
116*0fca6ea1SDimitry Andric
117*0fca6ea1SDimitry Andric GEN_HAS_MEMBER(enable_sgpr_private_segment_wave_byte_offset)
118*0fca6ea1SDimitry Andric GEN_HAS_MEMBER(user_sgpr_count)
119*0fca6ea1SDimitry Andric GEN_HAS_MEMBER(enable_trap_handler)
120*0fca6ea1SDimitry Andric GEN_HAS_MEMBER(enable_sgpr_workgroup_id_x)
121*0fca6ea1SDimitry Andric GEN_HAS_MEMBER(enable_sgpr_workgroup_id_y)
122*0fca6ea1SDimitry Andric GEN_HAS_MEMBER(enable_sgpr_workgroup_id_z)
123*0fca6ea1SDimitry Andric GEN_HAS_MEMBER(enable_sgpr_workgroup_info)
124*0fca6ea1SDimitry Andric GEN_HAS_MEMBER(enable_vgpr_workitem_id)
125*0fca6ea1SDimitry Andric GEN_HAS_MEMBER(enable_exception_msb)
126*0fca6ea1SDimitry Andric GEN_HAS_MEMBER(granulated_lds_size)
127*0fca6ea1SDimitry Andric GEN_HAS_MEMBER(enable_exception)
128*0fca6ea1SDimitry Andric
129*0fca6ea1SDimitry Andric GEN_HAS_MEMBER(enable_sgpr_private_segment_buffer)
130*0fca6ea1SDimitry Andric GEN_HAS_MEMBER(enable_sgpr_dispatch_ptr)
131*0fca6ea1SDimitry Andric GEN_HAS_MEMBER(enable_sgpr_queue_ptr)
132*0fca6ea1SDimitry Andric GEN_HAS_MEMBER(enable_sgpr_kernarg_segment_ptr)
133*0fca6ea1SDimitry Andric GEN_HAS_MEMBER(enable_sgpr_dispatch_id)
134*0fca6ea1SDimitry Andric GEN_HAS_MEMBER(enable_sgpr_flat_scratch_init)
135*0fca6ea1SDimitry Andric GEN_HAS_MEMBER(enable_sgpr_private_segment_size)
136*0fca6ea1SDimitry Andric GEN_HAS_MEMBER(enable_sgpr_grid_workgroup_count_x)
137*0fca6ea1SDimitry Andric GEN_HAS_MEMBER(enable_sgpr_grid_workgroup_count_y)
138*0fca6ea1SDimitry Andric GEN_HAS_MEMBER(enable_sgpr_grid_workgroup_count_z)
139*0fca6ea1SDimitry Andric GEN_HAS_MEMBER(enable_wavefront_size32)
140*0fca6ea1SDimitry Andric GEN_HAS_MEMBER(enable_ordered_append_gds)
141*0fca6ea1SDimitry Andric GEN_HAS_MEMBER(private_element_size)
142*0fca6ea1SDimitry Andric GEN_HAS_MEMBER(is_ptr64)
143*0fca6ea1SDimitry Andric GEN_HAS_MEMBER(is_dynamic_callstack)
144*0fca6ea1SDimitry Andric GEN_HAS_MEMBER(is_debug_enabled)
145*0fca6ea1SDimitry Andric GEN_HAS_MEMBER(is_xnack_enabled)
146*0fca6ea1SDimitry Andric
147*0fca6ea1SDimitry Andric GEN_HAS_MEMBER(workitem_private_segment_byte_size)
148*0fca6ea1SDimitry Andric GEN_HAS_MEMBER(workgroup_group_segment_byte_size)
149*0fca6ea1SDimitry Andric GEN_HAS_MEMBER(gds_segment_byte_size)
150*0fca6ea1SDimitry Andric GEN_HAS_MEMBER(kernarg_segment_byte_size)
151*0fca6ea1SDimitry Andric GEN_HAS_MEMBER(workgroup_fbarrier_count)
152*0fca6ea1SDimitry Andric GEN_HAS_MEMBER(wavefront_sgpr_count)
153*0fca6ea1SDimitry Andric GEN_HAS_MEMBER(workitem_vgpr_count)
154*0fca6ea1SDimitry Andric GEN_HAS_MEMBER(reserved_vgpr_first)
155*0fca6ea1SDimitry Andric GEN_HAS_MEMBER(reserved_vgpr_count)
156*0fca6ea1SDimitry Andric GEN_HAS_MEMBER(reserved_sgpr_first)
157*0fca6ea1SDimitry Andric GEN_HAS_MEMBER(reserved_sgpr_count)
158*0fca6ea1SDimitry Andric GEN_HAS_MEMBER(debug_wavefront_private_segment_offset_sgpr)
159*0fca6ea1SDimitry Andric GEN_HAS_MEMBER(debug_private_segment_buffer_sgpr)
160*0fca6ea1SDimitry Andric GEN_HAS_MEMBER(kernarg_segment_alignment)
161*0fca6ea1SDimitry Andric GEN_HAS_MEMBER(group_segment_alignment)
162*0fca6ea1SDimitry Andric GEN_HAS_MEMBER(private_segment_alignment)
163*0fca6ea1SDimitry Andric GEN_HAS_MEMBER(wavefront_size)
164*0fca6ea1SDimitry Andric GEN_HAS_MEMBER(call_convention)
165*0fca6ea1SDimitry Andric GEN_HAS_MEMBER(runtime_loader_kernel_symbol)
166*0fca6ea1SDimitry Andric
167*0fca6ea1SDimitry Andric static ArrayRef<StringLiteral> get_amd_kernel_code_t_FldNames() {
168*0fca6ea1SDimitry Andric static constexpr StringLiteral const Table[] = {
1690b57cec5SDimitry Andric "", // not found placeholder
1700b57cec5SDimitry Andric #define RECORD(name, altName, print, parse) #name
171*0fca6ea1SDimitry Andric #include "Utils/AMDKernelCodeTInfo.h"
1720b57cec5SDimitry Andric #undef RECORD
1730b57cec5SDimitry Andric };
174bdd1243dSDimitry Andric return ArrayRef(Table);
1750b57cec5SDimitry Andric }
1760b57cec5SDimitry Andric
get_amd_kernel_code_t_FldAltNames()177*0fca6ea1SDimitry Andric static ArrayRef<StringLiteral> get_amd_kernel_code_t_FldAltNames() {
178*0fca6ea1SDimitry Andric static constexpr StringLiteral const Table[] = {
1790b57cec5SDimitry Andric "", // not found placeholder
1800b57cec5SDimitry Andric #define RECORD(name, altName, print, parse) #altName
181*0fca6ea1SDimitry Andric #include "Utils/AMDKernelCodeTInfo.h"
1820b57cec5SDimitry Andric #undef RECORD
1830b57cec5SDimitry Andric };
184bdd1243dSDimitry Andric return ArrayRef(Table);
1850b57cec5SDimitry Andric }
1860b57cec5SDimitry Andric
hasMCExprVersionTable()187*0fca6ea1SDimitry Andric static ArrayRef<bool> hasMCExprVersionTable() {
188*0fca6ea1SDimitry Andric static bool const Table[] = {
189*0fca6ea1SDimitry Andric #define RECORD(name, altName, print, parse) (IsMCExpr##name::RESULT)
190*0fca6ea1SDimitry Andric #include "Utils/AMDKernelCodeTInfo.h"
191*0fca6ea1SDimitry Andric #undef RECORD
192*0fca6ea1SDimitry Andric };
193*0fca6ea1SDimitry Andric return ArrayRef(Table);
194*0fca6ea1SDimitry Andric }
195*0fca6ea1SDimitry Andric
196*0fca6ea1SDimitry Andric using RetrieveFx = const MCExpr *&(*)(AMDGPUMCKernelCodeT &);
197*0fca6ea1SDimitry Andric
getMCExprIndexTable()198*0fca6ea1SDimitry Andric static ArrayRef<RetrieveFx> getMCExprIndexTable() {
199*0fca6ea1SDimitry Andric static const RetrieveFx Table[] = {
200*0fca6ea1SDimitry Andric #define RECORD(name, altName, print, parse) GetMember##name::Get
201*0fca6ea1SDimitry Andric #include "Utils/AMDKernelCodeTInfo.h"
202*0fca6ea1SDimitry Andric #undef RECORD
203*0fca6ea1SDimitry Andric };
204*0fca6ea1SDimitry Andric return ArrayRef(Table);
205*0fca6ea1SDimitry Andric }
206*0fca6ea1SDimitry Andric
createIndexMap(ArrayRef<StringLiteral> names,ArrayRef<StringLiteral> altNames)207*0fca6ea1SDimitry Andric static StringMap<int> createIndexMap(ArrayRef<StringLiteral> names,
208*0fca6ea1SDimitry Andric ArrayRef<StringLiteral> altNames) {
2090b57cec5SDimitry Andric StringMap<int> map;
2100b57cec5SDimitry Andric assert(names.size() == altNames.size());
2110b57cec5SDimitry Andric for (unsigned i = 0; i < names.size(); ++i) {
212bdd1243dSDimitry Andric map.insert(std::pair(names[i], i));
213bdd1243dSDimitry Andric map.insert(std::pair(altNames[i], i));
2140b57cec5SDimitry Andric }
2150b57cec5SDimitry Andric return map;
2160b57cec5SDimitry Andric }
2170b57cec5SDimitry Andric
get_amd_kernel_code_t_FieldIndex(StringRef name)2180b57cec5SDimitry Andric static int get_amd_kernel_code_t_FieldIndex(StringRef name) {
2190b57cec5SDimitry Andric static const auto map = createIndexMap(get_amd_kernel_code_t_FldNames(),
2200b57cec5SDimitry Andric get_amd_kernel_code_t_FldAltNames());
2210b57cec5SDimitry Andric return map.lookup(name) - 1; // returns -1 if not found
2220b57cec5SDimitry Andric }
2230b57cec5SDimitry Andric
224*0fca6ea1SDimitry Andric class PrintField {
225*0fca6ea1SDimitry Andric public:
226*0fca6ea1SDimitry Andric template <typename T, T AMDGPUMCKernelCodeT::*ptr,
227*0fca6ea1SDimitry Andric typename std::enable_if_t<!std::is_integral_v<T>, T> * = nullptr>
printField(StringRef Name,const AMDGPUMCKernelCodeT & C,raw_ostream & OS,MCContext & Ctx)228*0fca6ea1SDimitry Andric static void printField(StringRef Name, const AMDGPUMCKernelCodeT &C,
229*0fca6ea1SDimitry Andric raw_ostream &OS, MCContext &Ctx) {
230*0fca6ea1SDimitry Andric OS << Name << " = ";
231*0fca6ea1SDimitry Andric const MCExpr *Value = C.*ptr;
232*0fca6ea1SDimitry Andric int64_t Val;
233*0fca6ea1SDimitry Andric if (Value->evaluateAsAbsolute(Val))
234*0fca6ea1SDimitry Andric OS << Val;
235*0fca6ea1SDimitry Andric else
236*0fca6ea1SDimitry Andric Value->print(OS, Ctx.getAsmInfo());
2370b57cec5SDimitry Andric }
2380b57cec5SDimitry Andric
239*0fca6ea1SDimitry Andric template <typename T, T AMDGPUMCKernelCodeT::*ptr,
240*0fca6ea1SDimitry Andric typename std::enable_if_t<std::is_integral_v<T>, T> * = nullptr>
printField(StringRef Name,const AMDGPUMCKernelCodeT & C,raw_ostream & OS,MCContext &)241*0fca6ea1SDimitry Andric static void printField(StringRef Name, const AMDGPUMCKernelCodeT &C,
242*0fca6ea1SDimitry Andric raw_ostream &OS, MCContext &) {
243*0fca6ea1SDimitry Andric OS << Name << " = " << (int)(C.*ptr);
2440b57cec5SDimitry Andric }
245*0fca6ea1SDimitry Andric };
2460b57cec5SDimitry Andric
247*0fca6ea1SDimitry Andric template <typename T, T AMDGPUMCKernelCodeT::*ptr, int shift, int width = 1>
printBitField(StringRef Name,const AMDGPUMCKernelCodeT & C,raw_ostream & OS,MCContext &)248*0fca6ea1SDimitry Andric static void printBitField(StringRef Name, const AMDGPUMCKernelCodeT &C,
249*0fca6ea1SDimitry Andric raw_ostream &OS, MCContext &) {
2500b57cec5SDimitry Andric const auto Mask = (static_cast<T>(1) << width) - 1;
251*0fca6ea1SDimitry Andric OS << Name << " = " << (int)((C.*ptr >> shift) & Mask);
2520b57cec5SDimitry Andric }
2530b57cec5SDimitry Andric
254*0fca6ea1SDimitry Andric using PrintFx = void (*)(StringRef, const AMDGPUMCKernelCodeT &, raw_ostream &,
255*0fca6ea1SDimitry Andric MCContext &);
2560b57cec5SDimitry Andric
getPrinterTable()2570b57cec5SDimitry Andric static ArrayRef<PrintFx> getPrinterTable() {
2580b57cec5SDimitry Andric static const PrintFx Table[] = {
259*0fca6ea1SDimitry Andric #define COMPPGM1(name, aname, AccMacro) \
260*0fca6ea1SDimitry Andric COMPPGM(name, aname, C_00B848_##AccMacro, S_00B848_##AccMacro, 0)
261*0fca6ea1SDimitry Andric #define COMPPGM2(name, aname, AccMacro) \
262*0fca6ea1SDimitry Andric COMPPGM(name, aname, C_00B84C_##AccMacro, S_00B84C_##AccMacro, 32)
263*0fca6ea1SDimitry Andric #define PRINTFIELD(sname, aname, name) PrintField::printField<FLD_T(name)>
264*0fca6ea1SDimitry Andric #define PRINTCOMP(Complement, PGMType) \
265*0fca6ea1SDimitry Andric [](StringRef Name, const AMDGPUMCKernelCodeT &C, raw_ostream &OS, \
266*0fca6ea1SDimitry Andric MCContext &Ctx) { \
267*0fca6ea1SDimitry Andric OS << Name << " = "; \
268*0fca6ea1SDimitry Andric auto [Shift, Mask] = getShiftMask(Complement); \
269*0fca6ea1SDimitry Andric const MCExpr *Value; \
270*0fca6ea1SDimitry Andric if (PGMType == 0) { \
271*0fca6ea1SDimitry Andric Value = \
272*0fca6ea1SDimitry Andric maskShiftGet(C.compute_pgm_resource1_registers, Mask, Shift, Ctx); \
273*0fca6ea1SDimitry Andric } else { \
274*0fca6ea1SDimitry Andric Value = \
275*0fca6ea1SDimitry Andric maskShiftGet(C.compute_pgm_resource2_registers, Mask, Shift, Ctx); \
276*0fca6ea1SDimitry Andric } \
277*0fca6ea1SDimitry Andric int64_t Val; \
278*0fca6ea1SDimitry Andric if (Value->evaluateAsAbsolute(Val)) \
279*0fca6ea1SDimitry Andric OS << Val; \
280*0fca6ea1SDimitry Andric else \
281*0fca6ea1SDimitry Andric Value->print(OS, Ctx.getAsmInfo()); \
282*0fca6ea1SDimitry Andric }
2830b57cec5SDimitry Andric #define RECORD(name, altName, print, parse) print
284*0fca6ea1SDimitry Andric #include "Utils/AMDKernelCodeTInfo.h"
2850b57cec5SDimitry Andric #undef RECORD
2860b57cec5SDimitry Andric };
287bdd1243dSDimitry Andric return ArrayRef(Table);
2880b57cec5SDimitry Andric }
2890b57cec5SDimitry Andric
expectAbsExpression(MCAsmParser & MCParser,int64_t & Value,raw_ostream & Err)290*0fca6ea1SDimitry Andric static bool expectAbsExpression(MCAsmParser &MCParser, int64_t &Value,
291*0fca6ea1SDimitry Andric raw_ostream &Err) {
2920b57cec5SDimitry Andric
2930b57cec5SDimitry Andric if (MCParser.getLexer().isNot(AsmToken::Equal)) {
2940b57cec5SDimitry Andric Err << "expected '='";
2950b57cec5SDimitry Andric return false;
2960b57cec5SDimitry Andric }
2970b57cec5SDimitry Andric MCParser.getLexer().Lex();
2980b57cec5SDimitry Andric
2990b57cec5SDimitry Andric if (MCParser.parseAbsoluteExpression(Value)) {
3000b57cec5SDimitry Andric Err << "integer absolute expression expected";
3010b57cec5SDimitry Andric return false;
3020b57cec5SDimitry Andric }
3030b57cec5SDimitry Andric return true;
3040b57cec5SDimitry Andric }
3050b57cec5SDimitry Andric
306*0fca6ea1SDimitry Andric template <typename T, T AMDGPUMCKernelCodeT::*ptr>
parseField(AMDGPUMCKernelCodeT & C,MCAsmParser & MCParser,raw_ostream & Err)307*0fca6ea1SDimitry Andric static bool parseField(AMDGPUMCKernelCodeT &C, MCAsmParser &MCParser,
3080b57cec5SDimitry Andric raw_ostream &Err) {
3090b57cec5SDimitry Andric int64_t Value = 0;
3100b57cec5SDimitry Andric if (!expectAbsExpression(MCParser, Value, Err))
3110b57cec5SDimitry Andric return false;
3120b57cec5SDimitry Andric C.*ptr = (T)Value;
3130b57cec5SDimitry Andric return true;
3140b57cec5SDimitry Andric }
3150b57cec5SDimitry Andric
316*0fca6ea1SDimitry Andric template <typename T, T AMDGPUMCKernelCodeT::*ptr, int shift, int width = 1>
parseBitField(AMDGPUMCKernelCodeT & C,MCAsmParser & MCParser,raw_ostream & Err)317*0fca6ea1SDimitry Andric static bool parseBitField(AMDGPUMCKernelCodeT &C, MCAsmParser &MCParser,
3180b57cec5SDimitry Andric raw_ostream &Err) {
3190b57cec5SDimitry Andric int64_t Value = 0;
3200b57cec5SDimitry Andric if (!expectAbsExpression(MCParser, Value, Err))
3210b57cec5SDimitry Andric return false;
3220b57cec5SDimitry Andric const uint64_t Mask = ((UINT64_C(1) << width) - 1) << shift;
3230b57cec5SDimitry Andric C.*ptr &= (T)~Mask;
3240b57cec5SDimitry Andric C.*ptr |= (T)((Value << shift) & Mask);
3250b57cec5SDimitry Andric return true;
3260b57cec5SDimitry Andric }
3270b57cec5SDimitry Andric
parseExpr(MCAsmParser & MCParser,const MCExpr * & Value,raw_ostream & Err)328*0fca6ea1SDimitry Andric static bool parseExpr(MCAsmParser &MCParser, const MCExpr *&Value,
329*0fca6ea1SDimitry Andric raw_ostream &Err) {
330*0fca6ea1SDimitry Andric if (MCParser.getLexer().isNot(AsmToken::Equal)) {
331*0fca6ea1SDimitry Andric Err << "expected '='";
332*0fca6ea1SDimitry Andric return false;
333*0fca6ea1SDimitry Andric }
334*0fca6ea1SDimitry Andric MCParser.getLexer().Lex();
335*0fca6ea1SDimitry Andric
336*0fca6ea1SDimitry Andric if (MCParser.parseExpression(Value)) {
337*0fca6ea1SDimitry Andric Err << "Could not parse expression";
338*0fca6ea1SDimitry Andric return false;
339*0fca6ea1SDimitry Andric }
340*0fca6ea1SDimitry Andric return true;
341*0fca6ea1SDimitry Andric }
342*0fca6ea1SDimitry Andric
343*0fca6ea1SDimitry Andric using ParseFx = bool (*)(AMDGPUMCKernelCodeT &, MCAsmParser &, raw_ostream &);
3440b57cec5SDimitry Andric
getParserTable()3450b57cec5SDimitry Andric static ArrayRef<ParseFx> getParserTable() {
3460b57cec5SDimitry Andric static const ParseFx Table[] = {
347*0fca6ea1SDimitry Andric #define COMPPGM1(name, aname, AccMacro) \
348*0fca6ea1SDimitry Andric COMPPGM(name, aname, G_00B848_##AccMacro, C_00B848_##AccMacro, 0)
349*0fca6ea1SDimitry Andric #define COMPPGM2(name, aname, AccMacro) \
350*0fca6ea1SDimitry Andric COMPPGM(name, aname, G_00B84C_##AccMacro, C_00B84C_##AccMacro, 32)
351*0fca6ea1SDimitry Andric #define PARSECOMP(Complement, PGMType) \
352*0fca6ea1SDimitry Andric [](AMDGPUMCKernelCodeT &C, MCAsmParser &MCParser, \
353*0fca6ea1SDimitry Andric raw_ostream &Err) -> bool { \
354*0fca6ea1SDimitry Andric MCContext &Ctx = MCParser.getContext(); \
355*0fca6ea1SDimitry Andric const MCExpr *Value; \
356*0fca6ea1SDimitry Andric if (!parseExpr(MCParser, Value, Err)) \
357*0fca6ea1SDimitry Andric return false; \
358*0fca6ea1SDimitry Andric auto [Shift, Mask] = getShiftMask(Complement); \
359*0fca6ea1SDimitry Andric Value = maskShiftSet(Value, Mask, Shift, Ctx); \
360*0fca6ea1SDimitry Andric const MCExpr *Compl = MCConstantExpr::create(Complement, Ctx); \
361*0fca6ea1SDimitry Andric if (PGMType == 0) { \
362*0fca6ea1SDimitry Andric C.compute_pgm_resource1_registers = MCBinaryExpr::createAnd( \
363*0fca6ea1SDimitry Andric C.compute_pgm_resource1_registers, Compl, Ctx); \
364*0fca6ea1SDimitry Andric C.compute_pgm_resource1_registers = MCBinaryExpr::createOr( \
365*0fca6ea1SDimitry Andric C.compute_pgm_resource1_registers, Value, Ctx); \
366*0fca6ea1SDimitry Andric } else { \
367*0fca6ea1SDimitry Andric C.compute_pgm_resource2_registers = MCBinaryExpr::createAnd( \
368*0fca6ea1SDimitry Andric C.compute_pgm_resource2_registers, Compl, Ctx); \
369*0fca6ea1SDimitry Andric C.compute_pgm_resource2_registers = MCBinaryExpr::createOr( \
370*0fca6ea1SDimitry Andric C.compute_pgm_resource2_registers, Value, Ctx); \
371*0fca6ea1SDimitry Andric } \
372*0fca6ea1SDimitry Andric return true; \
373*0fca6ea1SDimitry Andric }
3740b57cec5SDimitry Andric #define RECORD(name, altName, print, parse) parse
375*0fca6ea1SDimitry Andric #include "Utils/AMDKernelCodeTInfo.h"
3760b57cec5SDimitry Andric #undef RECORD
3770b57cec5SDimitry Andric };
378bdd1243dSDimitry Andric return ArrayRef(Table);
3790b57cec5SDimitry Andric }
3800b57cec5SDimitry Andric
printAmdKernelCodeField(const AMDGPUMCKernelCodeT & C,int FldIndex,raw_ostream & OS,MCContext & Ctx)381*0fca6ea1SDimitry Andric static void printAmdKernelCodeField(const AMDGPUMCKernelCodeT &C, int FldIndex,
382*0fca6ea1SDimitry Andric raw_ostream &OS, MCContext &Ctx) {
383*0fca6ea1SDimitry Andric auto Printer = getPrinterTable()[FldIndex];
384*0fca6ea1SDimitry Andric if (Printer)
385*0fca6ea1SDimitry Andric Printer(get_amd_kernel_code_t_FldNames()[FldIndex + 1], C, OS, Ctx);
386*0fca6ea1SDimitry Andric }
387*0fca6ea1SDimitry Andric
initDefault(const MCSubtargetInfo * STI,MCContext & Ctx,bool InitMCExpr)388*0fca6ea1SDimitry Andric void AMDGPUMCKernelCodeT::initDefault(const MCSubtargetInfo *STI,
389*0fca6ea1SDimitry Andric MCContext &Ctx, bool InitMCExpr) {
390*0fca6ea1SDimitry Andric AMDGPUMCKernelCodeT();
391*0fca6ea1SDimitry Andric
392*0fca6ea1SDimitry Andric AMDGPU::initDefaultAMDKernelCodeT(*this, STI);
393*0fca6ea1SDimitry Andric
394*0fca6ea1SDimitry Andric if (InitMCExpr) {
395*0fca6ea1SDimitry Andric const MCExpr *ZeroExpr = MCConstantExpr::create(0, Ctx);
396*0fca6ea1SDimitry Andric compute_pgm_resource1_registers =
397*0fca6ea1SDimitry Andric MCConstantExpr::create(Lo_32(compute_pgm_resource_registers), Ctx);
398*0fca6ea1SDimitry Andric compute_pgm_resource2_registers =
399*0fca6ea1SDimitry Andric MCConstantExpr::create(Hi_32(compute_pgm_resource_registers), Ctx);
400*0fca6ea1SDimitry Andric is_dynamic_callstack = ZeroExpr;
401*0fca6ea1SDimitry Andric wavefront_sgpr_count = ZeroExpr;
402*0fca6ea1SDimitry Andric workitem_vgpr_count = ZeroExpr;
403*0fca6ea1SDimitry Andric workitem_private_segment_byte_size = ZeroExpr;
404*0fca6ea1SDimitry Andric }
405*0fca6ea1SDimitry Andric }
406*0fca6ea1SDimitry Andric
validate(const MCSubtargetInfo * STI,MCContext & Ctx)407*0fca6ea1SDimitry Andric void AMDGPUMCKernelCodeT::validate(const MCSubtargetInfo *STI, MCContext &Ctx) {
408*0fca6ea1SDimitry Andric int64_t Value;
409*0fca6ea1SDimitry Andric if (!compute_pgm_resource1_registers->evaluateAsAbsolute(Value))
410*0fca6ea1SDimitry Andric return;
411*0fca6ea1SDimitry Andric
412*0fca6ea1SDimitry Andric if (G_00B848_DX10_CLAMP(Value) && AMDGPU::isGFX12Plus(*STI)) {
413*0fca6ea1SDimitry Andric Ctx.reportError({}, "enable_dx10_clamp=1 is not allowed on GFX12+");
414*0fca6ea1SDimitry Andric return;
415*0fca6ea1SDimitry Andric }
416*0fca6ea1SDimitry Andric
417*0fca6ea1SDimitry Andric if (G_00B848_IEEE_MODE(Value) && AMDGPU::isGFX12Plus(*STI)) {
418*0fca6ea1SDimitry Andric Ctx.reportError({}, "enable_ieee_mode=1 is not allowed on GFX12+");
419*0fca6ea1SDimitry Andric return;
420*0fca6ea1SDimitry Andric }
421*0fca6ea1SDimitry Andric
422*0fca6ea1SDimitry Andric if (G_00B848_WGP_MODE(Value) && !AMDGPU::isGFX10Plus(*STI)) {
423*0fca6ea1SDimitry Andric Ctx.reportError({}, "enable_wgp_mode=1 is only allowed on GFX10+");
424*0fca6ea1SDimitry Andric return;
425*0fca6ea1SDimitry Andric }
426*0fca6ea1SDimitry Andric
427*0fca6ea1SDimitry Andric if (G_00B848_MEM_ORDERED(Value) && !AMDGPU::isGFX10Plus(*STI)) {
428*0fca6ea1SDimitry Andric Ctx.reportError({}, "enable_mem_ordered=1 is only allowed on GFX10+");
429*0fca6ea1SDimitry Andric return;
430*0fca6ea1SDimitry Andric }
431*0fca6ea1SDimitry Andric
432*0fca6ea1SDimitry Andric if (G_00B848_FWD_PROGRESS(Value) && !AMDGPU::isGFX10Plus(*STI)) {
433*0fca6ea1SDimitry Andric Ctx.reportError({}, "enable_fwd_progress=1 is only allowed on GFX10+");
434*0fca6ea1SDimitry Andric return;
435*0fca6ea1SDimitry Andric }
436*0fca6ea1SDimitry Andric }
437*0fca6ea1SDimitry Andric
getMCExprForIndex(int Index)438*0fca6ea1SDimitry Andric const MCExpr *&AMDGPUMCKernelCodeT::getMCExprForIndex(int Index) {
439*0fca6ea1SDimitry Andric static const auto IndexTable = getMCExprIndexTable();
440*0fca6ea1SDimitry Andric return IndexTable[Index](*this);
441*0fca6ea1SDimitry Andric }
442*0fca6ea1SDimitry Andric
ParseKernelCodeT(StringRef ID,MCAsmParser & MCParser,raw_ostream & Err)443*0fca6ea1SDimitry Andric bool AMDGPUMCKernelCodeT::ParseKernelCodeT(StringRef ID, MCAsmParser &MCParser,
4440b57cec5SDimitry Andric raw_ostream &Err) {
4450b57cec5SDimitry Andric const int Idx = get_amd_kernel_code_t_FieldIndex(ID);
4460b57cec5SDimitry Andric if (Idx < 0) {
4470b57cec5SDimitry Andric Err << "unexpected amd_kernel_code_t field name " << ID;
4480b57cec5SDimitry Andric return false;
4490b57cec5SDimitry Andric }
450*0fca6ea1SDimitry Andric
451*0fca6ea1SDimitry Andric if (hasMCExprVersionTable()[Idx]) {
452*0fca6ea1SDimitry Andric const MCExpr *Value;
453*0fca6ea1SDimitry Andric if (!parseExpr(MCParser, Value, Err))
454*0fca6ea1SDimitry Andric return false;
455*0fca6ea1SDimitry Andric getMCExprForIndex(Idx) = Value;
456*0fca6ea1SDimitry Andric return true;
457*0fca6ea1SDimitry Andric }
4580b57cec5SDimitry Andric auto Parser = getParserTable()[Idx];
459*0fca6ea1SDimitry Andric return Parser ? Parser(*this, MCParser, Err) : false;
460*0fca6ea1SDimitry Andric }
461*0fca6ea1SDimitry Andric
EmitKernelCodeT(raw_ostream & OS,MCContext & Ctx)462*0fca6ea1SDimitry Andric void AMDGPUMCKernelCodeT::EmitKernelCodeT(raw_ostream &OS, MCContext &Ctx) {
463*0fca6ea1SDimitry Andric const int Size = hasMCExprVersionTable().size();
464*0fca6ea1SDimitry Andric for (int i = 0; i < Size; ++i) {
465*0fca6ea1SDimitry Andric OS << "\t\t";
466*0fca6ea1SDimitry Andric if (hasMCExprVersionTable()[i]) {
467*0fca6ea1SDimitry Andric OS << get_amd_kernel_code_t_FldNames()[i + 1] << " = ";
468*0fca6ea1SDimitry Andric int64_t Val;
469*0fca6ea1SDimitry Andric const MCExpr *Value = getMCExprForIndex(i);
470*0fca6ea1SDimitry Andric if (Value->evaluateAsAbsolute(Val))
471*0fca6ea1SDimitry Andric OS << Val;
472*0fca6ea1SDimitry Andric else
473*0fca6ea1SDimitry Andric Value->print(OS, Ctx.getAsmInfo());
474*0fca6ea1SDimitry Andric } else {
475*0fca6ea1SDimitry Andric printAmdKernelCodeField(*this, i, OS, Ctx);
476*0fca6ea1SDimitry Andric }
477*0fca6ea1SDimitry Andric OS << '\n';
478*0fca6ea1SDimitry Andric }
479*0fca6ea1SDimitry Andric }
480*0fca6ea1SDimitry Andric
EmitKernelCodeT(MCStreamer & OS,MCContext & Ctx)481*0fca6ea1SDimitry Andric void AMDGPUMCKernelCodeT::EmitKernelCodeT(MCStreamer &OS, MCContext &Ctx) {
482*0fca6ea1SDimitry Andric OS.emitIntValue(amd_kernel_code_version_major, /*Size=*/4);
483*0fca6ea1SDimitry Andric OS.emitIntValue(amd_kernel_code_version_minor, /*Size=*/4);
484*0fca6ea1SDimitry Andric OS.emitIntValue(amd_machine_kind, /*Size=*/2);
485*0fca6ea1SDimitry Andric OS.emitIntValue(amd_machine_version_major, /*Size=*/2);
486*0fca6ea1SDimitry Andric OS.emitIntValue(amd_machine_version_minor, /*Size=*/2);
487*0fca6ea1SDimitry Andric OS.emitIntValue(amd_machine_version_stepping, /*Size=*/2);
488*0fca6ea1SDimitry Andric OS.emitIntValue(kernel_code_entry_byte_offset, /*Size=*/8);
489*0fca6ea1SDimitry Andric OS.emitIntValue(kernel_code_prefetch_byte_offset, /*Size=*/8);
490*0fca6ea1SDimitry Andric OS.emitIntValue(kernel_code_prefetch_byte_size, /*Size=*/8);
491*0fca6ea1SDimitry Andric OS.emitIntValue(reserved0, /*Size=*/8);
492*0fca6ea1SDimitry Andric
493*0fca6ea1SDimitry Andric if (compute_pgm_resource1_registers != nullptr)
494*0fca6ea1SDimitry Andric OS.emitValue(compute_pgm_resource1_registers, /*Size=*/4);
495*0fca6ea1SDimitry Andric else
496*0fca6ea1SDimitry Andric OS.emitIntValue(Lo_32(compute_pgm_resource_registers),
497*0fca6ea1SDimitry Andric /*Size=*/4);
498*0fca6ea1SDimitry Andric
499*0fca6ea1SDimitry Andric if (compute_pgm_resource2_registers != nullptr)
500*0fca6ea1SDimitry Andric OS.emitValue(compute_pgm_resource2_registers, /*Size=*/4);
501*0fca6ea1SDimitry Andric else
502*0fca6ea1SDimitry Andric OS.emitIntValue(Hi_32(compute_pgm_resource_registers),
503*0fca6ea1SDimitry Andric /*Size=*/4);
504*0fca6ea1SDimitry Andric
505*0fca6ea1SDimitry Andric if (is_dynamic_callstack != nullptr) {
506*0fca6ea1SDimitry Andric const MCExpr *CodeProps = MCConstantExpr::create(code_properties, Ctx);
507*0fca6ea1SDimitry Andric CodeProps = MCBinaryExpr::createOr(
508*0fca6ea1SDimitry Andric CodeProps,
509*0fca6ea1SDimitry Andric maskShiftSet(is_dynamic_callstack,
510*0fca6ea1SDimitry Andric (1 << AMD_CODE_PROPERTY_IS_DYNAMIC_CALLSTACK_WIDTH) - 1,
511*0fca6ea1SDimitry Andric AMD_CODE_PROPERTY_IS_DYNAMIC_CALLSTACK_SHIFT, Ctx),
512*0fca6ea1SDimitry Andric Ctx);
513*0fca6ea1SDimitry Andric OS.emitValue(CodeProps, /*Size=*/4);
514*0fca6ea1SDimitry Andric } else
515*0fca6ea1SDimitry Andric OS.emitIntValue(code_properties, /*Size=*/4);
516*0fca6ea1SDimitry Andric
517*0fca6ea1SDimitry Andric if (workitem_private_segment_byte_size != nullptr)
518*0fca6ea1SDimitry Andric OS.emitValue(workitem_private_segment_byte_size, /*Size=*/4);
519*0fca6ea1SDimitry Andric else
520*0fca6ea1SDimitry Andric OS.emitIntValue(0, /*Size=*/4);
521*0fca6ea1SDimitry Andric
522*0fca6ea1SDimitry Andric OS.emitIntValue(workgroup_group_segment_byte_size, /*Size=*/4);
523*0fca6ea1SDimitry Andric OS.emitIntValue(gds_segment_byte_size, /*Size=*/4);
524*0fca6ea1SDimitry Andric OS.emitIntValue(kernarg_segment_byte_size, /*Size=*/8);
525*0fca6ea1SDimitry Andric OS.emitIntValue(workgroup_fbarrier_count, /*Size=*/4);
526*0fca6ea1SDimitry Andric
527*0fca6ea1SDimitry Andric if (wavefront_sgpr_count != nullptr)
528*0fca6ea1SDimitry Andric OS.emitValue(wavefront_sgpr_count, /*Size=*/2);
529*0fca6ea1SDimitry Andric else
530*0fca6ea1SDimitry Andric OS.emitIntValue(0, /*Size=*/2);
531*0fca6ea1SDimitry Andric
532*0fca6ea1SDimitry Andric if (workitem_vgpr_count != nullptr)
533*0fca6ea1SDimitry Andric OS.emitValue(workitem_vgpr_count, /*Size=*/2);
534*0fca6ea1SDimitry Andric else
535*0fca6ea1SDimitry Andric OS.emitIntValue(0, /*Size=*/2);
536*0fca6ea1SDimitry Andric
537*0fca6ea1SDimitry Andric OS.emitIntValue(reserved_vgpr_first, /*Size=*/2);
538*0fca6ea1SDimitry Andric OS.emitIntValue(reserved_vgpr_count, /*Size=*/2);
539*0fca6ea1SDimitry Andric OS.emitIntValue(reserved_sgpr_first, /*Size=*/2);
540*0fca6ea1SDimitry Andric OS.emitIntValue(reserved_sgpr_count, /*Size=*/2);
541*0fca6ea1SDimitry Andric OS.emitIntValue(debug_wavefront_private_segment_offset_sgpr,
542*0fca6ea1SDimitry Andric /*Size=*/2);
543*0fca6ea1SDimitry Andric OS.emitIntValue(debug_private_segment_buffer_sgpr, /*Size=*/2);
544*0fca6ea1SDimitry Andric OS.emitIntValue(kernarg_segment_alignment, /*Size=*/1);
545*0fca6ea1SDimitry Andric OS.emitIntValue(group_segment_alignment, /*Size=*/1);
546*0fca6ea1SDimitry Andric OS.emitIntValue(private_segment_alignment, /*Size=*/1);
547*0fca6ea1SDimitry Andric OS.emitIntValue(wavefront_size, /*Size=*/1);
548*0fca6ea1SDimitry Andric
549*0fca6ea1SDimitry Andric OS.emitIntValue(call_convention, /*Size=*/4);
550*0fca6ea1SDimitry Andric OS.emitBytes(StringRef((const char *)reserved3, /*Size=*/12));
551*0fca6ea1SDimitry Andric OS.emitIntValue(runtime_loader_kernel_symbol, /*Size=*/8);
552*0fca6ea1SDimitry Andric OS.emitBytes(StringRef((const char *)control_directives, /*Size=*/16 * 8));
5530b57cec5SDimitry Andric }
554