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