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
25using namespace llvm;
26
27static 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
37static 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
47static 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
58static 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
64static 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
70static raw_ostream &printName(raw_ostream &OS, StringRef Name) {
71  return OS << Name << " = ";
72}
73
74template <typename T, T amd_kernel_code_t::*ptr>
75static void printField(StringRef Name, const amd_kernel_code_t &C,
76                       raw_ostream &OS) {
77  printName(OS, Name) << (int)(C.*ptr);
78}
79
80template <typename T, T amd_kernel_code_t::*ptr, int shift, int width = 1>
81static 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
87using PrintFx = void(*)(StringRef, const amd_kernel_code_t &, raw_ostream &);
88
89static 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
98void 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
106void 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
119static 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
134template <typename T, T amd_kernel_code_t::*ptr>
135static 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
144template <typename T, T amd_kernel_code_t::*ptr, int shift, int width = 1>
145static 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
156using ParseFx = bool(*)(amd_kernel_code_t &, MCAsmParser &MCParser,
157                        raw_ostream &Err);
158
159static 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
168bool 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