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