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