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