xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/AMDGPU/Utils/AMDKernelCodeTUtils.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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)
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 
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 
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 
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 
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 
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>
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>
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>
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 
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 
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>
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>
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 
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 
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 
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 
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 
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 
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 
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 
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 
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