1 //===- AMDKernelCodeTUtils.cpp --------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 /// \file - utility functions to parse/print amd_kernel_code_t structure 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "AMDKernelCodeTUtils.h" 14 #include "SIDefines.h" 15 #include "llvm/ADT/ArrayRef.h" 16 #include "llvm/ADT/StringMap.h" 17 #include "llvm/ADT/StringRef.h" 18 #include "llvm/MC/MCParser/MCAsmLexer.h" 19 #include "llvm/MC/MCParser/MCAsmParser.h" 20 #include "llvm/Support/raw_ostream.h" 21 #include <cassert> 22 #include <cstdint> 23 #include <utility> 24 25 using namespace llvm; 26 27 static ArrayRef<StringRef> get_amd_kernel_code_t_FldNames() { 28 static StringRef const Table[] = { 29 "", // not found placeholder 30 #define RECORD(name, altName, print, parse) #name 31 #include "AMDKernelCodeTInfo.h" 32 #undef RECORD 33 }; 34 return makeArrayRef(Table); 35 } 36 37 static ArrayRef<StringRef> get_amd_kernel_code_t_FldAltNames() { 38 static StringRef const Table[] = { 39 "", // not found placeholder 40 #define RECORD(name, altName, print, parse) #altName 41 #include "AMDKernelCodeTInfo.h" 42 #undef RECORD 43 }; 44 return makeArrayRef(Table); 45 } 46 47 static StringMap<int> createIndexMap(const ArrayRef<StringRef> &names, 48 const ArrayRef<StringRef> &altNames) { 49 StringMap<int> map; 50 assert(names.size() == altNames.size()); 51 for (unsigned i = 0; i < names.size(); ++i) { 52 map.insert(std::make_pair(names[i], i)); 53 map.insert(std::make_pair(altNames[i], i)); 54 } 55 return map; 56 } 57 58 static int get_amd_kernel_code_t_FieldIndex(StringRef name) { 59 static const auto map = createIndexMap(get_amd_kernel_code_t_FldNames(), 60 get_amd_kernel_code_t_FldAltNames()); 61 return map.lookup(name) - 1; // returns -1 if not found 62 } 63 64 static StringRef get_amd_kernel_code_t_FieldName(int index) { 65 return get_amd_kernel_code_t_FldNames()[index + 1]; 66 } 67 68 // Field printing 69 70 static raw_ostream &printName(raw_ostream &OS, StringRef Name) { 71 return OS << Name << " = "; 72 } 73 74 template <typename T, T amd_kernel_code_t::*ptr> 75 static void printField(StringRef Name, const amd_kernel_code_t &C, 76 raw_ostream &OS) { 77 printName(OS, Name) << (int)(C.*ptr); 78 } 79 80 template <typename T, T amd_kernel_code_t::*ptr, int shift, int width = 1> 81 static void printBitField(StringRef Name, const amd_kernel_code_t &c, 82 raw_ostream &OS) { 83 const auto Mask = (static_cast<T>(1) << width) - 1; 84 printName(OS, Name) << (int)((c.*ptr >> shift) & Mask); 85 } 86 87 using PrintFx = void(*)(StringRef, const amd_kernel_code_t &, raw_ostream &); 88 89 static ArrayRef<PrintFx> getPrinterTable() { 90 static const PrintFx Table[] = { 91 #define RECORD(name, altName, print, parse) print 92 #include "AMDKernelCodeTInfo.h" 93 #undef RECORD 94 }; 95 return makeArrayRef(Table); 96 } 97 98 void llvm::printAmdKernelCodeField(const amd_kernel_code_t &C, 99 int FldIndex, 100 raw_ostream &OS) { 101 auto Printer = getPrinterTable()[FldIndex]; 102 if (Printer) 103 Printer(get_amd_kernel_code_t_FieldName(FldIndex), C, OS); 104 } 105 106 void llvm::dumpAmdKernelCode(const amd_kernel_code_t *C, 107 raw_ostream &OS, 108 const char *tab) { 109 const int Size = getPrinterTable().size(); 110 for (int i = 0; i < Size; ++i) { 111 OS << tab; 112 printAmdKernelCodeField(*C, i, OS); 113 OS << '\n'; 114 } 115 } 116 117 // Field parsing 118 119 static bool expectAbsExpression(MCAsmParser &MCParser, int64_t &Value, raw_ostream& Err) { 120 121 if (MCParser.getLexer().isNot(AsmToken::Equal)) { 122 Err << "expected '='"; 123 return false; 124 } 125 MCParser.getLexer().Lex(); 126 127 if (MCParser.parseAbsoluteExpression(Value)) { 128 Err << "integer absolute expression expected"; 129 return false; 130 } 131 return true; 132 } 133 134 template <typename T, T amd_kernel_code_t::*ptr> 135 static bool parseField(amd_kernel_code_t &C, MCAsmParser &MCParser, 136 raw_ostream &Err) { 137 int64_t Value = 0; 138 if (!expectAbsExpression(MCParser, Value, Err)) 139 return false; 140 C.*ptr = (T)Value; 141 return true; 142 } 143 144 template <typename T, T amd_kernel_code_t::*ptr, int shift, int width = 1> 145 static bool parseBitField(amd_kernel_code_t &C, MCAsmParser &MCParser, 146 raw_ostream &Err) { 147 int64_t Value = 0; 148 if (!expectAbsExpression(MCParser, Value, Err)) 149 return false; 150 const uint64_t Mask = ((UINT64_C(1) << width) - 1) << shift; 151 C.*ptr &= (T)~Mask; 152 C.*ptr |= (T)((Value << shift) & Mask); 153 return true; 154 } 155 156 using ParseFx = bool(*)(amd_kernel_code_t &, MCAsmParser &MCParser, 157 raw_ostream &Err); 158 159 static ArrayRef<ParseFx> getParserTable() { 160 static const ParseFx Table[] = { 161 #define RECORD(name, altName, print, parse) parse 162 #include "AMDKernelCodeTInfo.h" 163 #undef RECORD 164 }; 165 return makeArrayRef(Table); 166 } 167 168 bool llvm::parseAmdKernelCodeField(StringRef ID, 169 MCAsmParser &MCParser, 170 amd_kernel_code_t &C, 171 raw_ostream &Err) { 172 const int Idx = get_amd_kernel_code_t_FieldIndex(ID); 173 if (Idx < 0) { 174 Err << "unexpected amd_kernel_code_t field name " << ID; 175 return false; 176 } 177 auto Parser = getParserTable()[Idx]; 178 return Parser ? Parser(C, MCParser, Err) : false; 179 } 180