OpenASIP  2.0
Enumerations | Functions
tceopgen.cc File Reference
#include <iostream>
#include <fstream>
#include <set>
#include <assert.h>
#include "OperationPool.hh"
#include "Operation.hh"
#include "Conversion.hh"
#include "OperationIndex.hh"
#include "Operand.hh"
#include "Application.hh"
Include dependency graph for tceopgen.cc:

Go to the source code of this file.

Enumerations

enum  mode { NORMAL, FU_ADDRESSABLE, ADDRESSPACE, RISCV }
 

Functions

std::string operandTypeCString (const Operand &operand)
 
void writeCustomOpMacro (std::ostream &os, std::string &opName, const Operation &op, mode macroMode, bool legacy)
 
void writeCustomOpMacros (std::ostream &os)
 
int main (int argc, char *argv[])
 

Enumeration Type Documentation

◆ mode

enum mode

TCE custom op macro header generator for LLVM TCE backend.

Author
Veli-Pekka Jääskeläinen 2007 (vjaaskel-no.spam-cs.tut.fi)
Pekka Jääskeläinen 2009 (pjaaskel-no.spam-cs.tut.fi)
Note
rating: red
Enumerator
NORMAL 
FU_ADDRESSABLE 
ADDRESSPACE 
RISCV 

Definition at line 45 of file tceopgen.cc.

Function Documentation

◆ main()

int main ( int  argc,
char *  argv[] 
)

tceopgen main function.

Generates plugin sourcecode files using TDGen.

Definition at line 315 of file tceopgen.cc.

315  {
316 
317  if (!(argc == 1 || argc == 3) ||
318  (argc == 3 && Conversion::toString(argv[1]) != std::string("-o"))) {
319 
320  std::cout << "Usage: tceopgen" << std::endl
321  << " -o Output File." << std::endl;
322  return EXIT_FAILURE;
323  }
324 
325  if (argc == 1) {
326  writeCustomOpMacros(std::cout);
327  } else if (argc == 3) {
328  std::ofstream customops;
329  customops.open(argv[2]);
330  if (!customops.good()) {
331  std::cerr << "Error opening '" << argv[2]
332  << "' for writing." << std::endl;
333  return EXIT_FAILURE;
334  }
335  writeCustomOpMacros(customops);
336  customops.close();
337  } else {
338  assert(false);
339  }
340 
341  return EXIT_SUCCESS;
342 }

References assert, Conversion::toString(), and writeCustomOpMacros().

Here is the call graph for this function:

◆ operandTypeCString()

std::string operandTypeCString ( const Operand operand)

Returns a C type string for the given operand type.

Definition at line 50 of file tceopgen.cc.

50  {
51  switch (operand.type()) {
52  default:
53  case Operand::SINT_WORD:
54  return "int";
55  break;
56  case Operand::UINT_WORD:
57  return "unsigned";
58  break;
60  return "float";
61  break;
63  return "double";
64  break;
65  case Operand::RAW_DATA:
66  return "";
67  break;
69  return "long";
70  break;
72  return "unsigned long";
73  break;
74  }
75  // TODO: it never comes here!
76  // half floats take the "default".
77  return "unsigned";
78 }

References Operand::DOUBLE_WORD, Operand::FLOAT_WORD, Operand::RAW_DATA, Operand::SINT_WORD, Operand::SLONG_WORD, Operand::type(), Operand::UINT_WORD, and Operand::ULONG_WORD.

Referenced by writeCustomOpMacro().

Here is the call graph for this function:

◆ writeCustomOpMacro()

void writeCustomOpMacro ( std::ostream &  os,
std::string &  opName,
const Operation op,
mode  macroMode,
bool  legacy 
)

Produces the _TCE_OPNAME or _TCEFU_OPNAME macro that can be written to the tceops.h header file from the given operation.

Definition at line 85 of file tceopgen.cc.

87  {
88  // Only generate valid RISC-V R-format intrinsics
89  if (macroMode == RISCV) {
90  if (op.numberOfInputs() != 2) {
91  return;
92  }
93  if (op.numberOfOutputs() != 1) {
94  return;
95  }
96  }
97 
98  if (op.numberOfInputs() + op.numberOfOutputs() == 0)
99  return;
100 
101  if (legacy) {
102  os << "#define _TCE";
103  } else {
104  os << "#define _OA";
105  }
106 
107  const std::string outputOperandName =
108  legacy ? "__tce_op_output_" : "__oa_op_output_";
109 
110  switch (macroMode) {
111  case RISCV:
112  os << "_RV_" << opName << "(";
113  break;
114  case FU_ADDRESSABLE:
115  os << "FU_" << opName << "(FU, ";
116  break;
117  case ADDRESSPACE:
118  os << "AS_" << opName << "(AS, ";
119  break;
120  default:
121  os << "_" << opName << "(";
122  }
123 
124  int seenInputs = 0;
125  int seenOutputs = 0;
126  for (int i = 1;
127  i < (op.numberOfInputs() + op.numberOfOutputs() + 1);
128  i++) {
129 
130  const Operand& operand = op.operand(i);
131  if (i > 1)
132  os << ", ";
133  if (operand.isInput()) {
134  seenInputs++;
135  os << "i" << seenInputs;
136  } else {
137  seenOutputs++;
138  os << "o" << seenOutputs;
139  }
140  }
141 
142  os << ") do { ";
143 
144  /* Generate temporary variables to ensure casting to
145  a correct value from the inline assembly statement.
146 
147  Without this, LLVM inline assembly used i8 for the
148  output register type in case a char was used to
149  read the value. This produced strange errors due
150  to the value produced by the inline asm not being
151  masked to the char size (in case the output is really
152  larger than i8 in this case).
153 
154  In this bug (#35), after the char was written to
155  a larger variable, the upper bits (produced by the custom op)
156  were visible which is not expected behavior (writing int
157  to char should zero out the upper bits). Forcing
158  writing to int ensures the inline asm has 32 bit
159  reg for the register thus LLVM produced correct
160  masking/cast operations when writing the value to a smaller
161  variable.
162 
163  Use do {} while(0) block instead of {} to allow using the
164  custom ops as statements which end with ; etc.
165 
166  NOTE: we cannot add "memory" to the clobber list with
167  operations that write to memory because it seems to crash
168  (some versions of) gcc. Thus, they are marked 'volatile'.
169  */
170 
171  for (int out = 1; out < op.numberOfOutputs() + 1; out++) {
172  const Operand& operand = op.output(out - 1);
173  std::string operandTypeString = operandTypeCString(operand);
174  if (operandTypeString != "" && !operand.isVector()) {
175  os << operandTypeCString(operand) << " " << outputOperandName
176  << out << " = (" << operandTypeCString(operand) << ")0; ";
177  }
178  }
179 
180  std::string volatileKeyword = "";
181  if (op.writesMemory() || op.hasSideEffects() ||
182  op.affectsCount() > 0 || op.affectedByCount() > 0) {
183  volatileKeyword = "volatile ";
184  }
185 
186  os << "asm " << volatileKeyword << "(";
187 
188  switch (macroMode) {
189  case RISCV: {
190  os << "\"//" << opName << " ";
191  int iterations = 0;
192  for (iterations = 0; iterations < op.numberOfInputs();
193  iterations++) {
194  os << "\\%" << std::to_string(iterations) << " ";
195  }
196  for (int i = 0; i < op.numberOfOutputs(); i++) {
197  os << "\\%" << std::to_string(iterations + i);
198  }
199  } break;
200  case FU_ADDRESSABLE:
201  os << "FU\".";
202  break;
203  case ADDRESSPACE:
204  os << "\"_AS.\" AS\".";
205  break;
206  default:
207  os << "\"";
208  break;
209  }
210 
211  if (macroMode != RISCV) {
212  os << opName;
213  }
214  os << "\":";
215 
216  for (int out = 1; out < op.numberOfOutputs() + 1; out++) {
217  const Operand& operand = op.output(out - 1);
218 
219  if (out > 1)
220  os << ", ";
221  if (operandTypeCString(operand) != "" && !operand.isVector()) {
222  os << "\"=r\"( " << outputOperandName << out << ")";
223  } else {
224  os << "\"=r\"(o" << out << ")";
225  }
226  }
227  os << ":";
228 
229  for (int in = 1; in < op.numberOfInputs() + 1; in++) {
230  const Operand& operand = op.input(in - 1);
231 
232  if (in > 1)
233  os << ", ";
234  // Only register inputs for RISC-V
235  if (macroMode == RISCV) {
236  if (operandTypeCString(operand) != "") {
237  os << "\"r\"((" << operandTypeCString(operand) << ")(i" << in
238  << "))";
239  } else {
240  os << "\"r\"(i" << in << ")";
241  }
242  } else if (operandTypeCString(operand) != "" && !operand.isVector()) {
243  os << "\"ir\"((" << operandTypeCString(operand)
244  << ")(i" << in << "))";
245  } else {
246  if (operand.isVector()) {
247  os << "\"r\"(i" << in << ")";
248  } else {
249  os << "\"ir\"(i" << in << ")";
250  }
251  }
252  }
253 
254  os << "); ";
255 
256  // write the results from the temps to the output variables
257  for (int out = 1; out < op.numberOfOutputs() + 1; out++) {
258  const Operand& operand = op.output(out - 1);
259  if (operandTypeCString(operand) != "" && !operand.isVector()) {
260  os << "o" << out << " = " << outputOperandName << out << ";";
261  }
262  }
263 
264  os << "} while(0) " << std::endl;
265 }

References ADDRESSPACE, Operation::affectedByCount(), Operation::affectsCount(), FU_ADDRESSABLE, Operation::hasSideEffects(), Operation::input(), Operand::isInput(), Operand::isVector(), Operation::numberOfInputs(), Operation::numberOfOutputs(), Operation::operand(), operandTypeCString(), Operation::output(), RISCV, and Operation::writesMemory().

Referenced by writeCustomOpMacros().

Here is the call graph for this function:

◆ writeCustomOpMacros()

void writeCustomOpMacros ( std::ostream &  os)

Produces the _TCE_OPNAME and _TCEFU_OPNAME macros that can be written to the tceops.h header file.

Definition at line 272 of file tceopgen.cc.

272  {
273 
274  OperationPool pool;
275  OperationIndex& index = pool.index();
276  std::set<std::string> operations;
277 
278  for (int m = 0; m < index.moduleCount(); m++) {
279  OperationModule& mod = index.module(m);
280  try {
281  int opCount = index.operationCount(mod);
282  for (int o = 0; o < opCount; o++) {
283 
284  std::string opName = index.operationName(o, mod);
285  if (operations.count(opName) > 0) {
286  continue;
287  }
288  const Operation& op = pool.operation(opName.c_str());
289  operations.insert(opName);
290  // Write both legacy and new macros
291  writeCustomOpMacro(os, opName, op, NORMAL, true);
292  writeCustomOpMacro(os, opName, op, NORMAL, false);
293  writeCustomOpMacro(os, opName, op, RISCV, true);
294  writeCustomOpMacro(os, opName, op, RISCV, false);
295  writeCustomOpMacro(os, opName, op, FU_ADDRESSABLE, true);
296  writeCustomOpMacro(os, opName, op, FU_ADDRESSABLE, false);
297  if (op.usesMemory()) {
298  writeCustomOpMacro(os, opName, op, ADDRESSPACE, true);
299  writeCustomOpMacro(os, opName, op, ADDRESSPACE, false);
300  }
301  }
302  } catch (const Exception& e) {
304  << "ERROR: " << e.errorMessage() << std::endl;
305  continue;
306  }
307  }
308 }

References ADDRESSPACE, Exception::errorMessage(), Application::errorStream(), FU_ADDRESSABLE, OperationPool::index(), OperationIndex::module(), OperationIndex::moduleCount(), NORMAL, OperationPool::operation(), OperationIndex::operationCount(), OperationIndex::operationName(), RISCV, Operation::usesMemory(), and writeCustomOpMacro().

Referenced by main().

Here is the call graph for this function:
Operand
Definition: Operand.hh:52
Operation::affectedByCount
virtual int affectedByCount() const
Definition: Operation.cc:416
Operation::writesMemory
virtual bool writesMemory() const
Definition: Operation.cc:252
OperationPool::operation
Operation & operation(const char *name)
Definition: OperationPool.cc:99
Operation::hasSideEffects
virtual bool hasSideEffects() const
Definition: Operation.cc:272
Operation::output
virtual Operand & output(int index) const
Definition: Operation.cc:526
Operand::UINT_WORD
@ UINT_WORD
Definition: Operand.hh:60
OperationPool::index
OperationIndex & index()
Definition: OperationPool.cc:109
Operation::numberOfInputs
virtual int numberOfInputs() const
Definition: Operation.cc:192
writeCustomOpMacro
void writeCustomOpMacro(std::ostream &os, std::string &opName, const Operation &op, mode macroMode, bool legacy)
Definition: tceopgen.cc:85
Conversion::toString
static std::string toString(const T &source)
writeCustomOpMacros
void writeCustomOpMacros(std::ostream &os)
Definition: tceopgen.cc:272
assert
#define assert(condition)
Definition: Application.hh:86
Operand::isVector
virtual bool isVector() const
Definition: Operand.cc:268
Operand::SLONG_WORD
@ SLONG_WORD
Definition: Operand.hh:66
Operand::FLOAT_WORD
@ FLOAT_WORD
Definition: Operand.hh:61
RISCV
@ RISCV
Definition: tceopgen.cc:45
ADDRESSPACE
@ ADDRESSPACE
Definition: tceopgen.cc:45
NORMAL
@ NORMAL
Definition: tceopgen.cc:45
Operand::SINT_WORD
@ SINT_WORD
Definition: Operand.hh:59
Exception
Definition: Exception.hh:54
Operand::ULONG_WORD
@ ULONG_WORD
Definition: Operand.hh:67
Operand::RAW_DATA
@ RAW_DATA
Definition: Operand.hh:65
Operation
Definition: Operation.hh:59
Exception::errorMessage
std::string errorMessage() const
Definition: Exception.cc:123
FU_ADDRESSABLE
@ FU_ADDRESSABLE
Definition: tceopgen.cc:45
Operation::input
virtual Operand & input(int index) const
Definition: Operation.cc:503
Operation::usesMemory
virtual bool usesMemory() const
Definition: Operation.cc:232
Operand::DOUBLE_WORD
@ DOUBLE_WORD
Definition: Operand.hh:62
Operation::operand
virtual Operand & operand(int id) const
Definition: Operation.cc:541
OperationIndex::moduleCount
int moduleCount() const
Application::errorStream
static std::ostream & errorStream()
Definition: Application.cc:171
Operand::type
virtual OperandType type() const
Definition: Operand.cc:165
OperationModule
Definition: OperationModule.hh:46
operandTypeCString
std::string operandTypeCString(const Operand &operand)
Definition: tceopgen.cc:50
OperationIndex
Definition: OperationIndex.hh:58
OperationPool
Definition: OperationPool.hh:52
Operand::isInput
virtual bool isInput() const
Definition: Operand.cc:145
OperationIndex::operationCount
int operationCount(const OperationModule &om)
Definition: OperationIndex.cc:363
Operation::numberOfOutputs
virtual int numberOfOutputs() const
Definition: Operation.cc:202
OperationIndex::module
OperationModule & module(int i)
Operation::affectsCount
virtual int affectsCount() const
Definition: Operation.cc:402
OperationIndex::operationName
std::string operationName(int i, const OperationModule &om)
Definition: OperationIndex.cc:337