OpenASIP 2.2
Loading...
Searching...
No Matches
tceopgen.cc
Go to the documentation of this file.
1/*
2 Copyright (c) 2002-2009 Tampere University.
3
4 This file is part of TTA-Based Codesign Environment (TCE).
5
6 Permission is hereby granted, free of charge, to any person obtaining a
7 copy of this software and associated documentation files (the "Software"),
8 to deal in the Software without restriction, including without limitation
9 the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 and/or sell copies of the Software, and to permit persons to whom the
11 Software is furnished to do so, subject to the following conditions:
12
13 The above copyright notice and this permission notice shall be included in
14 all copies or substantial portions of the Software.
15
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 DEALINGS IN THE SOFTWARE.
23 */
24/**
25 * TCE custom op macro header generator for LLVM TCE backend.
26 *
27 * @author Veli-Pekka Jääskeläinen 2007 (vjaaskel-no.spam-cs.tut.fi)
28 * @author Pekka Jääskeläinen 2009 (pjaaskel-no.spam-cs.tut.fi)
29 *
30 * @note rating: red
31 */
32
33#include <iostream>
34#include <fstream>
35#include <set>
36#include <assert.h>
37
38#include "OperationPool.hh"
39#include "Operation.hh"
40#include "Conversion.hh"
41#include "OperationIndex.hh"
42#include "Operand.hh"
43#include "Application.hh"
44
46/**
47 * Returns a C type string for the given operand type.
48 */
49std::string
50operandTypeCString(const Operand& operand) {
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}
79
80/**
81 * Produces the _TCE_OPNAME or _TCEFU_OPNAME macro that can be written to the
82 * tceops.h header file from the given operation.
83 */
84void
86 std::ostream& os, std::string& opName, const Operation& op,
87 mode macroMode, bool legacy) {
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}
261
262/**
263 * Produces the _TCE_OPNAME and _TCEFU_OPNAME macros that can be
264 * written to the tceops.h header file.
265 */
266void
267writeCustomOpMacros(std::ostream& os) {
268
269 OperationPool pool;
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}
304
305/**
306 * tceopgen main function.
307 *
308 * Generates plugin sourcecode files using TDGen.
309 */
310int main(int argc, char* argv[]) {
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}
338
#define assert(condition)
static std::ostream & errorStream()
static std::string toString(const T &source)
std::string errorMessage() const
Definition Exception.cc:123
virtual bool isVector() const
Definition Operand.cc:268
virtual bool isInput() const
Definition Operand.cc:145
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
std::string operationName(int i, const OperationModule &om)
OperationModule & module(int i)
int operationCount(const OperationModule &om)
int moduleCount() const
virtual int affectedByCount() const
Definition Operation.cc:416
virtual bool usesMemory() const
Definition Operation.cc:232
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
int main(int argc, char *argv[])
Definition tceopgen.cc:310
void writeCustomOpMacros(std::ostream &os)
Definition tceopgen.cc:267
mode
Definition tceopgen.cc:45
@ NORMAL
Definition tceopgen.cc:45
@ RISCV
Definition tceopgen.cc:45
@ FU_ADDRESSABLE
Definition tceopgen.cc:45
@ ADDRESSPACE
Definition tceopgen.cc:45
void writeCustomOpMacro(std::ostream &os, std::string &opName, const Operation &op, mode macroMode, bool legacy)
Definition tceopgen.cc:85
std::string operandTypeCString(const Operand &operand)
Definition tceopgen.cc:50