OpenASIP 2.2
Loading...
Searching...
No Matches
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.

@ NORMAL
Definition tceopgen.cc:45
@ RISCV
Definition tceopgen.cc:45
@ FU_ADDRESSABLE
Definition tceopgen.cc:45
@ ADDRESSPACE
Definition tceopgen.cc:45

Function Documentation

◆ main()

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

tceopgen main function.

Generates plugin sourcecode files using TDGen.

Definition at line 310 of file tceopgen.cc.

310 {
311
312 if (!(argc == 1 || argc == 3) ||
313 (argc == 3 && Conversion::toString(argv[1]) != std::string("-o"))) {
314
315 std::cout << "Usage: tceopgen" << std::endl
316 << " -o Output File." << std::endl;
317 return EXIT_FAILURE;
318 }
319
320 if (argc == 1) {
321 writeCustomOpMacros(std::cout);
322 } else if (argc == 3) {
323 std::ofstream customops;
324 customops.open(argv[2]);
325 if (!customops.good()) {
326 std::cerr << "Error opening '" << argv[2]
327 << "' for writing." << std::endl;
328 return EXIT_FAILURE;
329 }
330 writeCustomOpMacros(customops);
331 customops.close();
332 } else {
333 assert(false);
334 }
335
336 return EXIT_SUCCESS;
337}
#define assert(condition)
static std::string toString(const T &source)
void writeCustomOpMacros(std::ostream &os)
Definition tceopgen.cc:267

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:
54 return "int";
55 break;
57 return "unsigned";
58 break;
60 return "float";
61 break;
63 return "double";
64 break;
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}
virtual OperandType type() const
Definition Operand.cc:165
@ SLONG_WORD
Definition Operand.hh:66
@ FLOAT_WORD
Definition Operand.hh:61
@ ULONG_WORD
Definition Operand.hh:67
@ RAW_DATA
Definition Operand.hh:65
@ SINT_WORD
Definition Operand.hh:59
@ DOUBLE_WORD
Definition Operand.hh:62
@ UINT_WORD
Definition Operand.hh:60

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

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 267 of file tceopgen.cc.

267 {
268
270 OperationIndex& index = pool.index();
271 std::set<std::string> operations;
272
273 for (int m = 0; m < index.moduleCount(); m++) {
274 OperationModule& mod = index.module(m);
275 try {
276 int opCount = index.operationCount(mod);
277 for (int o = 0; o < opCount; o++) {
278
279 std::string opName = index.operationName(o, mod);
280 if (operations.count(opName) > 0) {
281 continue;
282 }
283 const Operation& op = pool.operation(opName.c_str());
284 operations.insert(opName);
285 // Write both legacy and new macros
286 writeCustomOpMacro(os, opName, op, NORMAL, true);
287 writeCustomOpMacro(os, opName, op, NORMAL, false);
288 writeCustomOpMacro(os, opName, op, RISCV, true);
289 writeCustomOpMacro(os, opName, op, RISCV, false);
290 writeCustomOpMacro(os, opName, op, FU_ADDRESSABLE, true);
291 writeCustomOpMacro(os, opName, op, FU_ADDRESSABLE, false);
292 if (op.usesMemory()) {
293 writeCustomOpMacro(os, opName, op, ADDRESSPACE, true);
294 writeCustomOpMacro(os, opName, op, ADDRESSPACE, false);
295 }
296 }
297 } catch (const Exception& e) {
299 << "ERROR: " << e.errorMessage() << std::endl;
300 continue;
301 }
302 }
303}
static std::ostream & errorStream()
std::string errorMessage() const
Definition Exception.cc:123
std::string operationName(int i, const OperationModule &om)
OperationModule & module(int i)
int operationCount(const OperationModule &om)
int moduleCount() const
virtual bool usesMemory() const
Definition Operation.cc:232
std::unique_ptr< OperationPool > pool
void writeCustomOpMacro(std::ostream &os, std::string &opName, const Operation &op, mode macroMode, bool legacy)
Definition tceopgen.cc:85

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

Referenced by main().

Here is the call graph for this function: