OpenASIP 2.2
Loading...
Searching...
No Matches
TDGen.cc
Go to the documentation of this file.
1 /*
2 Copyright (c) 2002-2020 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 * Architecture plugin generator for LLVM TCE backend.
26 *
27 * @author Veli-Pekka Jääskeläinen 2007 (vjaaskel-no.spam-cs.tut.fi)
28 * @author Mikael Lepistö 2009 (mikael.lepisto-no.spam-tut.fi)
29 * @author Pekka Jääskeläinen 2010-2011
30 * @author Heikki Kultala 2012
31 *
32 * @note rating: red
33 */
34
35#include <fstream>
36#include <algorithm>
37
38#include "TDGen.hh"
39#include "Machine.hh"
40#include "ADFSerializer.hh"
41#include "ControlUnit.hh"
42#include "Operation.hh"
43#include "HWOperation.hh"
44#include "FUPort.hh"
45#include "Conversion.hh"
47#include "ImmediateAnalyzer.hh"
48#include "ImmInfo.hh"
49#include "Bus.hh"
50#include "Guard.hh"
51#include "StringTools.hh"
52#include "OperationPool.hh"
53#include "OperationNode.hh"
54#include "TerminalNode.hh"
55#include "ConstantNode.hh"
56#include "OperationDAG.hh"
57#include "OperationDAGEdge.hh"
59#include "TCEString.hh"
60#include "Operand.hh"
61#include "Application.hh"
62#include "LLVMBackend.hh" // llvmRequiredOps..
63#include "MathTools.hh"
64#include "tce_config.h"
66#include "MachineInfo.hh"
67
68// -----------
69/// @todo These two lines can be removed after C++11 features can be used in
70/// the source code, since it has native support for initializing std::map.
71#include "boost/assign.hpp"
72using namespace boost::assign;
73// -----------
74
75using std::endl;
76
77using namespace TDGenerator;
78
79// Vector value types that can be used in TTA machines.
80const std::set<TCEString> ValueType::SUPPORTED_LLVM_VALUE_TYPES =
81 list_of
82 ("v2i1") ("v4i1") ("v8i1") ("v16i1") // i1 subword
83 ("v2i8") ("v4i8") ("v8i8") ("v16i8") ("v32i8") // i8 subword
84 ("v2i16") ("v4i16") ("v8i16") ("v16i16") // i16 subword
85 ("v1i32") ("v2i32") ("v4i32") ("v8i32") ("v16i32") // i32 subword
86 ("v2f16") ("v4f16") ("v8f16") // f16 subword
87 ("v2f32") ("v4f32") ("v8f32") ("v16f32") // f32 subword
88 ("v32i1") ("v64i1") // i1 subword
89 ("v64i8") // i8 subword
90 ("v32i16") // i16 subword
91
92 ("v512i1") ("v1024i1") ("v128i8") ("v256i8")
93 ("v64i16") ("v128i16") ("v32i32") ("v64i32")
94
95 ("v128i1")
96 ("v2048i1")
97 ("v256i8") // i8 subword
98
99// New values that the custom vector extension patch unlocks.
100#if defined(LLVM_HAS_CUSTOM_VECTOR_EXTENSION)
101 ("v16f16") ("v32f16") ("v64f16") // f16 subword
102 ("v32f32") // f32 subword
103
104 ("v256i1")
105 ("v2048i1")
106 ("v128i1") // i1 subword
107
108// new wider extension, for up to 4096 bits
109#if LLVM_HAS_CUSTOM_VECTOR_EXTENSION == 2
110 ("v4096i1") ("v512i8") ("v256i16") ("v256f16") ("v128i32") ("v128f32")
111 ("v64f32") ("v128f16")
112
113#endif
114#endif
115;
116
117const int TDGen::FP_SUBW_WIDTH =
119const int TDGen::HFP_SUBW_WIDTH =
121const int TDGen::BOOL_SUBW_WIDTH =
123
124const int TDGen::MAX_SCALAR_WIDTH = 64;
125
126// Same as in generate_simd.py.in
128
129const bool TDGen::EXPLOIT_BIGGER_REGISTERS = true;
130
131// Operand type characters.
132const char TDGen::OT_REG_BOOL = 'b';
133const char TDGen::OT_REG_INT = 'r';
134const char TDGen::OT_REG_FP = 'f';
135const char TDGen::OT_REG_HFP = 'h';
136const char TDGen::OT_REG_LONG = 's';
137const char TDGen::OT_REG_DOUBLE = 'd';
138const char TDGen::OT_IMM_BOOL = 'j';
139const char TDGen::OT_IMM_INT = 'i';
140const char TDGen::OT_IMM_FP = 'k';
141const char TDGen::OT_IMM_HFP = 'l';
142const char TDGen::OT_IMM_LONG = 'a';
143const char TDGen::OT_VREG_BOOL = 'a';
144const char TDGen::OT_VREG_INT8 = 'q';
145const char TDGen::OT_VREG_INT16 = 't';
146const char TDGen::OT_VREG_INT32 = 'u';
147const char TDGen::OT_VREG_FP = 'e';
148const char TDGen::OT_VREG_HFP = 'g';
149
150// Operation base names (key) that have a pattern (value). Add new
151// OSAL vector operations here, which have an LLVM pattern.
152const std::map<TCEString, TCEString> TDGen::OPERATION_PATTERNS_ =
153 map_list_of
154 ("load","load %1%")
155 ("store","store %2%, %1%")
156
157 ("ld","load %1%")
158 ("ld8","load %1%")
159 ("ld16","load %1%")
160 ("ld32","load %1%")
161
162 ("st","store %2%, %1%")
163 ("st8","store %2%, %1%")
164 ("st16","store %2%, %1%")
165 ("st32","store %2%, %1%")
166
167 ("ldq","load %1%")
168 ("ldh","load %1%")
169 ("ldw","load %1%")
170 ("stq","store %2%, %1%")
171 ("sth","store %2%, %1%")
172 ("stw","store %2%, %1%")
173
174 ("not","not %1%")
175 ("and","and %1%, %2%")
176 ("ior","or %1%, %2%")
177 ("xor","xor %1%, %2%")
178 ("sxqh","sext %1%")
179 ("sxqw","sext %1%")
180 ("sxhw","sext %1%")
181 ("sxbw","sext %1%")
182 ("sxbh","sext %1%")
183 ("sxbq","sext %1%")
184 ("zxqh","zext %1%")
185 ("zxqw","zext %1%")
186 ("zxhw","zext %1%")
187 ("truncwh","trunc %1%")
188 ("truncwb","trunc %1%")
189 ("trunchb","trunc %1%")
190
191 ("shl","shl %1%, %2%")
192 ("shr","sra %1%, %2%")
193 ("shru","srl %1%, %2%")
194 ("add","add %1%, %2%")
195 ("sub","sub %1%, %2%")
196 ("mul","mul %1%, %2%")
197 ("div","sdiv %1%, %2%")
198 ("divu","udiv %1%, %2%")
199 ("eq","seteq %1%, %2%")
200 ("ne","setne %1%, %2%")
201 ("gt","setgt %1%, %2%")
202 ("gtu","setugt %1%, %2%")
203 ("ge","setge %1%, %2%")
204 ("geu","setuge %1%, %2%")
205 ("lt","setlt %1%, %2%")
206 ("ltu","setult %1%, %2%")
207 ("le","setle %1%, %2%")
208 ("leu","setule %1%, %2%")
209 ("mac","add %1%, (mul %2%, %3%)")
210
211 ("addf","fadd %1%, %2%")
212 ("subf","fsub %1%, %2%")
213 ("mulf","fmul %1%, %2%")
214 ("divf","fdiv %1%, %2%")
215 ("absf","fabs %1%")
216 ("negf","fneg %1%")
217 ("eqf","setoeq %1%, %2%")
218 ("equf","setueq %1%, %2%")
219 ("nef","setone %1%, %2%")
220 ("neuf","setune %1%, %2%")
221 ("gtf","setogt %1%, %2%")
222 ("gtuf","setugt %1%, %2%")
223 ("gef","setoge %1%, %2%")
224 ("geuf","setuge %1%, %2%")
225 ("ltf","setolt %1%, %2%")
226 ("ltuf","setult %1%, %2%")
227 ("lef","setole %1%, %2%")
228 ("leuf","setule %1%, %2%")
229 ("macf","fadd %1%, (fmul %2%, %3%)")
230 ("msuf","fsub %1%, (fmul %2%, %3%)")
231 ("cif","sint_to_fp %1%")
232 ("cfi","fp_to_sint %1%")
233 ("cifu","uint_to_fp %1%")
234 ("cfiu","fp_to_uint %1%")
235 ("sqrtf","fsqrt %1%")
236 ("chf","fpextend %1%")
237 ("cfh","fpround %1%")
238 ("csh","sint_to_fp %1%")
239 ("cshu","uint_to_fp %1%")
240 ("chs","fp_to_sint %1%")
241 ("chsu","fp_to_uint %1%")
242
243 ("addh","fadd %1%, %2%")
244 ("subh","fsub %1%, %2%")
245 ("mulh","fmul %1%, %2%")
246 ("divh","fdiv %1%, %2%")
247 ("absh","fabs %1%")
248 ("negh","fneg %1%")
249 ("eqh","setoeq %1%, %2%")
250 ("neh","setone %1%, %2%")
251 ("neuh","setune %1%, %2%")
252 ("gth","setogt %1%, %2%")
253 ("geh","setoge %1%, %2%")
254 ("lth","setolt %1%, %2%")
255 ("leh","setole %1%, %2%")
256 ("mach","fadd %1%, (fmul %2%, %3%)")
257 ("msuh","fsub %1%, (fmul %2%, %3%)")
258
259 ("vselect","vselect %3%, %1%, %2%")
260 ("insertelem","vector_insert %1%, %2%, %3%")
261 ("extractelem", "vector_extract %1%, %2%")
262 //("gather", "") /// @todo Once supported by LLVM
263 //("scatter", "") /// @todo Once supported by LLVM
264 // "pack" /// @note Has varying pattern, and thus, is generated separately.
265
266 // Utilization of the following vector operations is defined in the
267 // custom instruction selector since they don't have an LLVM pattern.
268 // "andsame"
269 // "iorsame"
270 // "xorsame"
271 // "shlsame"
272 // "shrsame"
273 // "shrusame"
274 // "vbcast"
275 // "vshuffle1"
276 // "vshuffle2"
277
278 // The following can be currently used only by invoking _TCE intrinsic.
279 // "unpack"
280 ;
281
282/**
283 * Custom comparator that orders operation names correctly number-wise.
284 *
285 * For instance, in an std::set operation names are ordered followingly:
286 * ADD32X16, ADD32X4, ADD32X8, XOR1024, XOR512, XOR64
287 *
288 * This function corrects the operation name order to be the following:
289 * ADD32X4, ADD32X8, ADD32X16, XOR64, XOR512, XOR1024
290 */
291bool
292numbersToAscending(const TCEString& lhs, const TCEString& rhs) {
293 size_t lhsI = lhs.length() - 1;
294 size_t rhsI = rhs.length() - 1;
295
296 // Reverse operation name to the position where the last number begins.
297 while (lhsI > 0 && std::isdigit(lhs[lhsI])) --lhsI;
298 while (rhsI > 0 && std::isdigit(rhs[rhsI])) --rhsI;
299
300 // Make sure both strings contain a number.
301 if (lhsI > 0 && lhsI != lhs.length() - 1 && rhsI > 0 &&
302 rhsI != rhs.length() - 1) {
303 // The string part before the number must match between both names.
304 if (lhs.substr(0, lhsI + 1) == rhs.substr(0, rhsI + 1)) {
305 // Make the smaller number precede the larger one.
306 try {
307 int lhsNumber = Conversion::toInt(lhs.substr(lhsI + 1));
308 int rhsNumber = Conversion::toInt(rhs.substr(rhsI + 1));
309 return lhsNumber < rhsNumber;
310 } catch (const NumberFormatException& e) {
312 }
313 }
314 }
315
316 // Basic comparison for std::string.
317 return lhs < rhs;
318}
319
320// SP, RES, KLUDGE, 2 GPRs?
321//unsigned const TDGen::REQUIRED_I32_REGS = 5;
322
323/* Leave this part (percent) of regs unallocated in each RF so
324 the scheduler's reg renamer always has some registers.
325 Rounds downwards.
326
327 This probably should be a progressive percentage. More regs you
328 have, less likely is that you need them to avoid spills and more
329 likely it is that the reg renamer can use them to remove restricting
330 antideps.
331*/
332static const unsigned REG_RENAMER_PART = 0;
333const std::string TDGen::guardRegTemplateName = "Guard";
334
335
336/**
337 * Constructor.
338 *
339 * @param mach Machine to generate plugin for.
340 */
341TDGen::TDGen(const TTAMachine::Machine& mach, bool initialize) :
342 mach_(mach), immInfo_(NULL), dregNum_(0), maxVectorSize_(0),
343 highestLaneInt_(-1), highestLaneBool_(-1),
344 hasExBoolRegs_(false), hasExIntRegs_(false), hasSelect_(false),
345 littleEndian_(mach.isLittleEndian()),
346 argRegCount_(1),
347 requiredI32Regs_(0), requiredI64Regs_(0), prebypassStackIndeces_(false),
348 use64bitForFP_(false) {
349 // These are TTA-specific, which we don't want to run for other targets
350 if (initialize) {
352
354
355 if (mach.is64bit()) {
356 std::set<int> scalarWidths { 1, 32 };
359
360 // TODO: this does not make sense! requires more!
363
364 } else {
365 std::set<int> scalarWidths { 1, 32 };
368
369 // TODO: this does not make sense! requires more!
372 }
374 maxScalarWidth_ = mach.is64bit() ? 64 : 32;
376 }
377
378}
379
380/**
381 * Destructor.
382 */
384 if (immInfo_ != NULL) {
385 delete immInfo_;
386 }
387}
388/*
389 * Initializes backend components so that they are not generated
390 * multiple times, as we need to use them both for hash generation
391 * and the *.td files.
392*/
393void
395 std::ostringstream registerInfoBuffer;
396 std::ostringstream addressingModeDefsBuffer;
397 std::ostringstream operandDefsBuffer;
398 std::ostringstream instrInfoBuffer;
399 std::ostringstream instrFormatsBuffer;
400 std::ostringstream callingConvBuffer;
401 std::ostringstream argRegsArrayBuffer;
402 std::ostringstream backendCodeBuffer;
403 std::ostringstream topLevelTDBuffer;
404
405 writeRegisterInfo(registerInfoBuffer);
406 writeAddressingModeDefs(addressingModeDefsBuffer);
407 writeOperandDefs(operandDefsBuffer);
408 writeInstrInfo(instrInfoBuffer);
409 writeInstrFormats(instrFormatsBuffer);
410 writeCallingConv(callingConvBuffer);
411 writeArgRegsArray(argRegsArrayBuffer);
412 writeBackendCode(backendCodeBuffer);
413 writeTopLevelTD(topLevelTDBuffer);
414
415 registerInfo_ = registerInfoBuffer.str();
416 addressingModeDefs_ = addressingModeDefsBuffer.str();
417 operandDefs_ = operandDefsBuffer.str();
418 instrInfo_ = instrInfoBuffer.str();
419 instrFormats_ = instrFormatsBuffer.str();
420 callingConv_ = callingConvBuffer.str();
421 argRegsArray_ = argRegsArrayBuffer.str();
422 backendCode_ = backendCodeBuffer.str();
423 topLevelTD_ = topLevelTDBuffer.str();
424}
425
426/**
427 * Generates all files required to build a tce backend plugin
428 * (excluding static plugin code included from include/llvm/TCE/).
429 */
430void
431TDGen::generateBackend(const std::string& path) const {
432 std::ofstream regTD;
433 regTD.open((path + "/GenRegisterInfo.td").c_str());
434 regTD << registerInfo_;
435 regTD.close();
436
437 std::ofstream instrTD0;
438 instrTD0.open((path + "/GenInstrInfo0.td").c_str());
439 instrTD0 << addressingModeDefs_;
440 instrTD0.close();
441
442 std::ofstream operandTD;
443 operandTD.open((path + "/GenOperandInfo.td").c_str());
444 operandTD << operandDefs_;
445 operandTD.close();
446
447 std::ofstream instrTD;
448 instrTD.open((path + "/GenInstrInfo.td").c_str());
449 instrTD << instrInfo_;
450#ifdef DEBUG_TDGEN
451 writeInstrInfo(std::cerr);
452#endif
453 instrTD.close();
454
455 std::ofstream formatTD;
456 formatTD.open((path + "/GenTCEInstrFormats.td").c_str());
457 formatTD << instrFormats_;
458 formatTD.close();
459
460 std::ofstream ccTD;
461 ccTD.open((path + "/GenCallingConv.td").c_str());
462 ccTD << callingConv_;
463 ccTD.close();
464
465 std::ofstream argArr;
466 argArr.open((path + "/ArgRegs.hh").c_str());
467 argArr << argRegsArray_;
468 argArr.close();
469
470 std::ofstream pluginInc;
471 pluginInc.open((path + "/Backend.inc").c_str());
472 pluginInc << backendCode_;
473 pluginInc.close();
474
475 std::ofstream topLevelTD;
476 topLevelTD.open((path + "/TCE.td").c_str());
477 topLevelTD << topLevelTD_;
478 topLevelTD.close();
479}
480
481/**
482 * Writes tce backend plugin code into a single string.
483 * Used for hash generation.
484 */
485std::string
487 const std::string buffer = registerInfo_ + addressingModeDefs_
490 return buffer;
491}
492
493/**
494 * Writes .td definition of a single register to the output stream.
495 *
496 * @param o Output stream to write the definition to.
497 * @param reg Information about the physical register.
498 * @param regName Name for the register in the llvm framework.
499 * @param regTemplate Base class for the register.
500 * @param aliases Comma-separated list of aliases for this register.
501 */
502void
504 std::ostream& o,
505 const RegInfo& reg,
506 const std::string regName,
507 const std::string regTemplate,
508 const std::string aliases,
509 RegType type) {
510
511 std::string templ = regTemplate;
512
513 o << "def " << regName << " : " << templ
514 << "<\"" << reg.rf << "." << reg.idx
515 << "\", [" << aliases << "]>, DwarfRegNum<"
516 << "[" << dregNum_ << "]>;"
517 << std::endl;
518
519
520 if (type == GPR) {
521 gprRegNames_.push_back(regName);
522 } else if (type == ARGUMENT) {
523 argRegNames_.push_back(regName);
524 } else if (type == RESULT) {
525 argRegNames_.push_back(regName);
526 resRegNames_.push_back(regName);
527 } else {
528 assert(type == RESERVED);
529 }
530
531 regs_[regName] = reg;
532
533 regsInClasses_[regTemplate].push_back(regName);
534
535 if (guardedRegs_.find(reg) != guardedRegs_.end()) {
536 llvmGuardRegs_.push_back(regName);
537 regsInClasses_[guardRegTemplateName].push_back(regName);
538 }
539
540 dregNum_++;
541}
542
543
544/**
545 * Writes .td definitions of all registers in the machine to an output stream.
546 *
547 * @param o Output stream for the .td definitions.
548 * @return True, if the definitions were succesfully generated.
549 */
550bool
551TDGen::writeRegisterInfo(std::ostream& o) {
553
554 if (!checkRequiredRegisters()) {
555 return false;
556 }
557
559
560 // Write scalar register information without old vector backend registers.
565// write16bitRegisterInfo(o); // currently not supported properly
568
569 // Gather and separate all operations to vector and scalar containers.
571
572 // Create register classes for vector operands.
574 // Group registers by width.
576 // Associate register groups properly with register classes.
578
579 // Write register related information to the .td file.
584
585 return true;
586}
587
588/**
589 * Writes static register info to the beginning of register info .td file.
590 *
591 * @param o Output stream to the file.
592 */
593void
595 o << "//" << endl;
596 o << "// This file is generated automatically!" << endl;
597 o << "// Do not edit." << endl;
598 o << "//" << endl;
599 o << endl;
600
601 o << "class TCEReg<string n, list<Register> aliases> : "
602 << "Register<n> {"
603 << endl;
604
605 o << " let Namespace = \"TCE\";" << endl;
606 o << " let Aliases = aliases;" << endl;
607 o << "}" << endl;
608 o << "class TCEVectorReg<string n, list<Register> subregs> : "
609 << "RegisterWithSubRegs<n, subregs> {"
610 << endl
611 << " let Namespace = \"TCE\";" << endl
612 << "}\n" << endl;
613}
614
615/**
616 * Writes all short immediate definitions to the stream.
617 *
618 * @param o The output stream.
619 */
620void
621TDGen::writeOperandDefs(std::ostream& o) {
622 assert(immInfo_ != nullptr
623 && "Short immediate analysis results are not available!");
624
625 o << "// Immediate definitions for TCE instructions." << std::endl;
626
628
629 o << std::endl;
630 o << "// Immediate definitions for immediate to register moves."
631 << std::endl;
633
634 o << std::endl;
635}
636
637/**
638 * Writes unique immediate operands (ImmLeafs) for all operations that can have
639 * short immediates to transported to theirs operands.
640 *
641 * The names of the immediate operands are stored in i32immOperandDefs_ map.
642 * Note: operations, that can not have short immediates to be trasported at
643 * all, do not entry in the map.
644 *
645 * @param o The output stream.
646 * @param iivs The immediate info.
647 */
648void
650 std::ostream& o,
651 const ImmInfo& iivs) {
652
653 TCEString immDefBaseName = mach_.is64bit() ? "i64imm" : "i32imm";
654 TCEString immDefType = mach_.is64bit() ? "i64" : "i32";
655 int bits = mach_.is64bit() ? 64 : 32;
656 using ImmBounds = std::pair<int64_t, int64_t>;
657
658 OperationPool opPool;
659 std::set<const Operation*> opset;
660 for (auto& iiv : iivs) {
661 const Operation& op = opPool.operation(iiv.first.first.c_str());
662 if (&op == &NullOperation::instance())
663 continue;
664 opset.insert(&op);
665 }
666
667 std::map<ImmBounds, std::string> immediateClasses;
668 int immId = 0;
669 for (auto op : opset) {
670 // Divide input operands into groups that can be swapped together.
671 // Commutative instructions with immediate operands in the patterns
672 // are defined having the immediate operands as last operands
673 // (e.g. ADDrri). For these a combined ImmLeaf is created (union of
674 // each of ImmLeaf of the inputs).
675 std::vector<std::set<int>> inputGroups;
676 for (int opdIdx = 1; opdIdx < op->numberOfInputs() + 1; opdIdx++) {
677 const Operand& opd = op->operand(opdIdx);
678
679 bool alreadyGrouped = false;
680 for (auto& group : inputGroups) {
681 if (group.count(opdIdx)) {
682 alreadyGrouped = true;
683 break;
684 }
685 }
686 if (alreadyGrouped) continue;
687
688 inputGroups.push_back(std::set<int>());
689 inputGroups.back().insert(opdIdx);
690 for (int otherOpdIdx : opd.swap()) {
691 inputGroups.back().insert(otherOpdIdx);
692 }
693 }
694
695 // For each input operand group assign an ImmLeaf operand definition.
696 // The names of ImmLeaf definitions are stored in immOperandDefs_,
697 // which is accessed using operation and operand as the key.
698 for (auto group : inputGroups) {
699 ImmBounds widestImmBound;
700 for (auto idx : group) {
701 // Determine max transportable immediate value range.
702 if (iivs.count(*op, idx)) {
703 // perform union
704 ImmBounds immBound = iivs.immediateValueBounds(
705 *op, idx, bits);
706 widestImmBound.first = std::min(
707 widestImmBound.first, immBound.first);
708 widestImmBound.second = std::max(
709 widestImmBound.second, immBound.second);
710 }
711 // Can not transport immediates at all.
712 if (widestImmBound == ImmBounds()) continue;
713
714 // immediateClasses stores unique encountered immediate value
715 // ranges.
716 if (immediateClasses.count(widestImmBound) == 0) {
717 std::string immDefName = std::string("i32imm")
718 + Conversion::toString(immId);
719 if (!mach_.is64bit()) {
720 immediateClasses[widestImmBound] = immDefName;
721 }
723 o, immDefName, "i32", immediatePredicate(
724 widestImmBound.first, widestImmBound.second));
725
726 immDefName = std::string("i64imm")
727 + Conversion::toString(immId);
728
729 if (mach_.is64bit()) {
730 immediateClasses[widestImmBound] = immDefName;
731 }
732
734 o, immDefName, "i64", immediatePredicate(
735 widestImmBound.first, widestImmBound.second));
736
737 immId++;
738
739 }
740 immOperandDefs_[ImmInfo::key(*op, idx)] =
741 immediateClasses.at(widestImmBound);
742 }
743 }
744 }
745}
746
747/**
748 * Writes immediate operand definitions that are used for MOV instructions.
749 *
750 * Creates immediate operand definitions for immediate to register instructions
751 * (MOVI), that only accept supported immediate values.
752 *
753 * @note Implemented currently only for i32 registers.
754 */
755void
757 using MCC = MachineConnectivityCheck;
758
759 TCEString immDefBaseName = mach_.is64bit() ? "i64imm" : "i32imm";
760 TCEString immDefType = mach_.is64bit() ? "i64" : "i32";
761 int bits = mach_.is64bit() ? 64 : 32;
762
763 std::pair<int64_t, uint64_t> moveImm{ 0, 0 };
764 for (auto& rf : mach_.registerFileNavigator()) {
765 if (rf->width() != bits) continue;
766
767 for (auto& bus : mach_.busNavigator()) {
768 if (!MCC::busConnectedToRF(*bus, *rf)
769 || bus->immediateWidth() == 0) {
770 continue;
771 }
772
773 if (bus->immediateWidth() >= bits) {
774 moveImm.first = -(1ll << (bits-1));
775 moveImm.second = (1ll << bits)-1;
776 break;
777 } else {
778 std::pair<int64_t, uint64_t> imm =
779 MathTools::bitsToIntegerRange<int64_t, uint64_t>(
780 bus->immediateWidth(),
781 bus->signExtends());
782
783 moveImm.first = std::min(moveImm.first, imm.first);
784 moveImm.second = std::max(moveImm.second, imm.second);
785 }
786 }
787 }
788
789 for (auto& iu : mach_.immediateUnitNavigator()) {
790 for (auto& it : mach_.instructionTemplateNavigator()) {
791 int supportedWidth = it->supportedWidth(*iu);
792 if (supportedWidth >= bits) {
793 moveImm.first = -(1ll << (bits-1));
794 moveImm.second = (1ll << bits)-1;
795 break;
796 } else {
797 std::pair<int64_t, uint64_t> imm =
798 MathTools::bitsToIntegerRange<int64_t, uint64_t>(
799 supportedWidth, iu->signExtends());
800
801 moveImm.first = std::min(moveImm.first, imm.first);
802 moveImm.second = std::max(moveImm.second, imm.second);
803 }
804 }
805 }
806
807 writeImmediateDef(o, "i32MoveImm", "i32", immediatePredicate(
808 moveImm.first, moveImm.second));
809
810 writeImmediateDef(o, "i64MoveImm", "i64", immediatePredicate(
811 moveImm.first, moveImm.second));
812
813}
814
815void
817
818 o << "class R1<string n, list<Register> aliases> : TCEReg<n, aliases> {"
819 << "}" << std::endl;
820
821 o << "class R32<string n, list<Register> aliases> : TCEReg<n, aliases> {"
822 << "}" << std::endl;
823
824 o << "class R64<string n, list<Register> aliases> : TCEReg<n, aliases> {"
825 << "}" << std::endl;
826
827
828 o << "class R16<string n, list<Register> aliases> : TCEReg<n, aliases> {"
829 << "}" << std::endl;
830}
831
832
833/**
834 * Iterates through all registers in the machine and adds register information
835 * to the register sets.
836 */
837void
839
842
843 // Check which registers have guards and put their info in
844 // guardedRegs_ set.
845 for (int i = 0; i < busNav.count(); i++) {
846 const TTAMachine::Bus& bus = *busNav.item(i);
847 for (int g = 0; g < bus.guardCount(); g++) {
848 const TTAMachine::RegisterGuard* rg =
849 dynamic_cast<const TTAMachine::RegisterGuard*>(bus.guard(g));
850
851 if (rg != NULL) {
852 RegInfo reg = {
853 rg->registerFile()->name(),
854 (unsigned)rg->registerIndex() };
855
856 guardedRegs_.insert(reg);
857 }
858 }
859 }
860
863
864 bool regsFound = true;
865 int currentIdx = 0;
866 while (regsFound) {
867 regsFound = false;
868 for (int i = 0; i < nav.count(); i++) {
869 const TTAMachine::RegisterFile* rf = nav.item(i);
870
871 // Skip definition for registers that are marked as 'reserved'
872 if (rf->isReserved()) continue;
873
874 // Skip the 0th index of a register file with zero register flag
875 if (currentIdx == 0 && rf->zeroRegister()) {
876 regsFound = true;
877 continue;
878 }
879
880 // Check that the registerfile has both input and output ports.
881 bool hasInput = false;
882 bool hasOutput = false;
883 for (int p = 0; p < rf->portCount(); p++) {
884 if (rf->port(p)->isInput()) hasInput = true;
885 if (rf->port(p)->isOutput()) hasOutput = true;
886 }
887
888 if (!hasInput) {
891
893 << "Warning: Skipping register file '"
894 << rf->name()
895 << "': no input ports."
896 << std::endl;
897 }
898 continue;
899 }
900
901 if (!hasOutput) {
904
906 << "Warning Skipping register file '"
907 << rf->name()
908 << "': no output ports."
909 << std::endl;
910 }
911 continue;
912 }
913
914 unsigned width = rf->width();
915 std::vector<RegInfo>* ri = NULL;
916 if (width == 64) ri = &regs64bit_;
917 else if (width == 32) ri = &regs32bit_;
918 //else if (width == 16) ri = &regs16bit_;
919 else if (width == 8) ri = &regs8bit_;
920 else if (width == 1) ri = &regs1bit_;
921 else {
922 continue;
923 }
924
925 int lastIdx = rf->size();
926 // todo: find a good solution to use just one big rf for this.
927
928 bool isTempRegRf = AssocTools::containsKey(tempRegFiles_, rf);
929 if (isTempRegRf) {
930 // If the machine is not enough connected,
931 // preserve last register
932 // of all register files for routing values.
933 lastIdx--;
934 }
935
936 // leave some 32bit regs unallocated for the post pass scheduler's
937 // register renamer
938 if (width == 32) {
939 int renamerRegs = rf->size() * REG_RENAMER_PART / 100;
940 lastIdx -= renamerRegs;
941 }
942
943 if (currentIdx < lastIdx) {
944 RegInfo reg = {rf->name(), (unsigned)currentIdx};
945 if (!(width == 32 &&
946 guardedRegs_.find(reg) != guardedRegs_.end())) {
947 ri->push_back(reg);
948 }
949 regsFound = true;
950 }
951 }
952 currentIdx++;
953 }
954}
955
956
957/**
958 * Writes 1-bit register definitions to the output stream.
959 */
960void
962 if (regs1bit_.size() < 1) {
963 RegInfo reg = {"dummy1", 0};
964 std::string name = "I1DUMMY";
965 writeRegisterDef(o, reg, name, "R1", "", RESERVED);
966 } else {
967 for (unsigned i = 0; i < regs1bit_.size(); i++) {
968 std::string regName = "B" + Conversion::toString(i);
969 writeRegisterDef(o, regs1bit_[i], regName, "R1", "", GPR);
970 }
971 }
972
973 int stackSize = mach_.is64bit() ? 64 : 32;
974 for (RegClassMap::iterator ri = regsInClasses_.begin();
975 ri != regsInClasses_.end(); ri++) {
976 // go through all 1-bit RF classes
977 if (ri->first.find("R1") == 0) {
978 o << std::endl
979 << "def " << ri->first << "Regs : RegisterClass<\"TCE\", [i1]"
980 << ", " << stackSize << ", (add ";
981 o << ri->second[0];
982 for (unsigned i = 1; i < ri->second.size(); i++) {
983 o << " , " << ri->second[i];
984 }
985 o << ")> {" << std::endl
986 << " let Size=" << stackSize << ";" << std::endl
987 << "}" << std::endl;
988 }
989 }
990}
991
992/**
993 * Gathers all machine op names and sorts them to vector and scalar
994 * operations.
995 */
996void
998 // Get all operation names to one container.
1000
1001 OperationPool opPool;
1002 OperationDAGSelector::OperationSet::const_iterator it;
1003 for (it = allOpNames_.begin(); it != allOpNames_.end(); ++it) {
1004 TCEString opName = *it;
1005 Operation* op = &opPool.operation(opName.c_str());
1006
1007 if (op != &NullOperation::instance()) {
1008 if (op->isVectorOperation()) {
1009 vectorOps_.insert(std::make_pair(opName, op));
1010 } else {
1011 scalarOps_.insert(std::make_pair(opName, op));
1012 }
1013 }
1014 }
1015}
1016
1017/*
1018 * Writes 32-bit register definitions to the output stream.
1019 */
1020void
1022
1023 std::string i32regs;
1024 size_t i = 0;
1025
1026 if (!mach_.is64bit()) {
1027 // --- Hardcoded reserved registers. ---
1028 writeRegisterDef(o, regs32bit_[0], "SP", "R32", "", RESERVED);
1029 writeRegisterDef(o, regs32bit_[1], "IRES0", "R32", "", RESULT);
1030 writeRegisterDef(o, regs32bit_[2], "FP", "R32", "", RESERVED);
1031
1034 o, regs32bit_[3], "KLUDGE_REGISTER", "R32", "", GPR);
1035 } else {
1037 o, regs32bit_[3], "KLUDGE_REGISTER", "R32", "", RESERVED);
1038 }
1039
1040 i32regs = "SP, IRES0, FP, KLUDGE_REGISTER";
1041
1042 //after the loop, i will have the index of first non-special reg.
1043 for (i = 4;
1044 i < std::min((size_t)argRegCount_ + 3, regs32bit_.size());
1045 i++) {
1046 std::string regName = "A" + Conversion::toString(i);
1047 writeRegisterDef(o, regs32bit_[i], regName, "R32", "", ARGUMENT);
1048 i32regs += ", ";
1049 i32regs += regName;
1050 }
1051 }
1052
1053 if (regs32bit_.size() < 1) {
1054 RegInfo reg = { "dummy32", 0 };
1055 writeRegisterDef(o, reg, "dummy32", "R64", "", RESERVED);
1056 o << "def R32Regs : RegisterClass<\"TCE\", [i32,f32,f16,i1], 32, (add dummy32)>;"
1057 << std::endl;
1058 o << "def R32IRegs : RegisterClass<\"TCE\", [i32], 32, (add dummy32)>;"
1059 << std::endl;
1060 o << "def R32FPRegs : RegisterClass<\"TCE\", [f32], 32, (add dummy32)>;"
1061 << std::endl;
1062 o << "def R32HFPRegs : RegisterClass<\"TCE\", [f16], 32, (add dummy32)>;"
1063 << std::endl;
1064 }
1065
1066 // Generate data structure that contain registers grouped by their
1067 // physical RFs
1068 for (; i < regs32bit_.size(); i++) {
1069 std::string regName = "I" + Conversion::toString(i);
1070 writeRegisterDef(o, regs32bit_[i], regName, "R32", "", GPR);
1071
1072 if (!regsInRFClasses_.count(regs32bit_[i].rf)) {
1073 regsInRFClasses_[regs32bit_[i].rf] = std::vector<std::string>();
1074 }
1075 i32regs += ", ";
1076 i32regs += regName;
1077 regsInRFClasses_[regs32bit_[i].rf].push_back(regName);
1078 }
1079
1080 o << std::endl;
1081
1082 if (!mach_.is64bit()) {
1083 // Bypass registers
1084 for (size_t j = 0; j < 256; ++j) {
1085 std::string regName = "BP" + Conversion::toString(j);
1086
1087 o << "def " << regName << " : "
1088 << "R32<\"ByPass_Regs"
1089 << "\", []>, DwarfRegNum<"
1090 << "[" << dregNum_++ << "]>;"
1091 << std::endl;
1092 }
1093
1094 // Bypass register class
1095 o << "def R32_ByPass_Regs : RegisterClass<\"TCE\", [i32,f32,f16], 32, (add ";
1096 for (size_t j = 0; j < 256; ++j) {
1097 std::string regName = "BP" + Conversion::toString(j);
1098
1099 if (j != 0) {
1100 o << ", ";
1101 }
1102
1103 o << regName;
1104 }
1105
1106 o << ")>;" << std::endl;
1107 }
1108
1109
1110 for (RegClassMap::iterator
1111 it = regsInRFClasses_.begin(); it != regsInRFClasses_.end(); ++it) {
1112 o << "def R32_"
1113 << it->first
1114 << "_Regs : RegisterClass<\"TCE\", [i32,f32,f16], 32, (add ";
1115
1116 for (std::vector<std::string>::iterator r = it->second.begin();
1117 r != it->second.end(); ++r) {
1118 if (r != it->second.begin()) {
1119 o << ", ";
1120 }
1121
1122 o << *r;
1123 }
1124
1125 o << ")>;" << std::endl;
1126 }
1127
1128 o << std::endl;
1129
1130 // Register classes for all 32-bit registers.
1131 // TODO: why are these needed? same as integer classes below?
1132 for (RegClassMap::iterator ri = regsInClasses_.begin();
1133 ri != regsInClasses_.end(); ri++) {
1134 // go through all 1-bit RF classes
1135 if (ri->first.find("R32") == 0) {
1136
1137 o << "def " << ri->first << "Regs : RegisterClass<\"TCE\", [i32,f32,f16,i1], 32, (add ";
1138 o << ri->second[0];
1139 for (unsigned i = 1; i < ri->second.size(); i++) {
1140 o << " , " << ri->second[i];
1141 }
1142 o << ")>;" << std::endl;
1143 }
1144 }
1145 o << std::endl;
1146
1147 // Integer register classes for 32-bit registers
1148 for (RegClassMap::iterator ri = regsInClasses_.begin();
1149 ri != regsInClasses_.end(); ri++) {
1150 // go through all 32-bit RF classes
1151 if (ri->first.find("R32") == 0) {
1152 o << "def " << ri->first << "IRegs : RegisterClass<\"TCE\", [i32], 32, (add ";
1153 o << ri->second[0];
1154 for (unsigned i = 1; i < ri->second.size(); i++) {
1155 o << " , " << ri->second[i];
1156 }
1157 o << ")>;" << std::endl;
1158 }
1159 }
1160 o << std::endl;
1161
1162 // Floating point register classes for 32-bit registers
1163 for (RegClassMap::iterator ri = regsInClasses_.begin();
1164 ri != regsInClasses_.end(); ri++) {
1165 // go through all 32-bit RF classes
1166 if (ri->first.find("R32") == 0) {
1167
1168 o << "def " << ri->first << "FPRegs : RegisterClass<\"TCE\", [f32], 32, (add ";
1169 o << ri->second[0];
1170 for (unsigned i = 1; i < ri->second.size(); i++) {
1171 o << " , " << ri->second[i];
1172 }
1173 o << ")>;" << std::endl;
1174 }
1175 }
1176
1177 // Half-float register classes for 32-bit registers (TODO: 16-bit registers also?)
1178 for (RegClassMap::iterator ri = regsInClasses_.begin();
1179 ri != regsInClasses_.end(); ri++) {
1180 // go through all 32-bit RF classes
1181 if (ri->first.find("R32") == 0) {
1182 o << "def " << ri->first << "HFPRegs : RegisterClass<\"TCE\", [f16], 32, (add ";
1183 o << ri->second[0];
1184 for (unsigned i = 1; i < ri->second.size(); i++) {
1185 o << " , " << ri->second[i];
1186 }
1187 o << ")>;" << std::endl;
1188 }
1189 }
1190
1191// if (regs32bit_.size() <3) {
1192 if (mach_.is64bit()) { // for now. later try to use 32-b it regs for float.
1193 use64bitForFP_ = true;
1194 }
1195
1196 if (!use64bitForFP_) {
1197
1198 o << "def FPRegs : RegisterClass<\"TCE\", [f32], 32, (add "
1199 << i32regs << ")>;" << std::endl;
1200
1201 o << "def HFPRegs : RegisterClass<\"TCE\", [f16], 32, (add "
1202 << i32regs << ")>;" << std::endl;
1203 }
1204 o << std::endl;
1205}
1206
1207/**
1208 * Writes 16-bit register definitions to the output stream.
1209 */
1210void
1212 // --- Hardcoded reserved registers. ---
1213 writeRegisterDef(o, regs16bit_[0], "HIRES0", "R16", "", RESULT);
1214
1215 // -------------------------------------
1216
1217 for (unsigned i = 1; i < regs16bit_.size(); i++) {
1218 std::string regName = "H" + Conversion::toString(i);
1219 writeRegisterDef(o, regs16bit_[i], regName, "R16", "", GPR);
1220 }
1221
1222 o << std::endl;
1223
1224 // All 16-bit regs.
1225 for (RegClassMap::iterator ri = regsInClasses_.begin();
1226 ri != regsInClasses_.end(); ri++) {
1227 // go through all 1-bit RF classes
1228 if (ri->first.find("R16") == 0) {
1229 o << "def " << ri->first
1230 << "Regs : RegisterClass<\"TCE\", [i16], 32, (add ";
1231 o << ri->second[0];
1232 for (unsigned i = 1; i < ri->second.size(); i++) {
1233 o << " , " << ri->second[i];
1234 }
1235 o << ")>;" << std::endl;
1236 }
1237 }
1238 o << std::endl;
1239
1240 for (RegClassMap::iterator ri = regsInClasses_.begin();
1241 ri != regsInClasses_.end(); ri++) {
1242 // go through all 1-bit RF classes
1243 if (ri->first.find("R16") == 0) {
1244 o << "def " << ri->first
1245 << "IRegs : RegisterClass<\"TCE\", [i16], 32, (add ";
1246 o << ri->second[0];
1247 for (unsigned i = 1; i < ri->second.size(); i++) {
1248 o << " , " << ri->second[i];
1249 }
1250 o << ")>;" << std::endl;
1251 }
1252 }
1253 o << std::endl;
1254
1255 // floating-point-versions of these
1256
1257 for (RegClassMap::iterator ri = regsInClasses_.begin();
1258 ri != regsInClasses_.end(); ri++) {
1259 // go through all 1-bit RF classes
1260 if (ri->first.find("R16") == 0) {
1261 o << "def " << ri->first
1262 << "FPRegs : RegisterClass<\"TCE\", [f16], 32, (add ";
1263 o << ri->second[0];
1264 for (unsigned i = 1; i < ri->second.size(); i++) {
1265 o << " , " << ri->second[i];
1266 }
1267 o << ")>;" << std::endl;
1268 }
1269 }
1270
1271 o << std::endl;
1272}
1273
1274/**
1275 * Creates vector register classes required by the machine.
1276 *
1277 * The function goes through all operations and lists all different vector
1278 * operand value types, after which a register class is created for each
1279 * vector value type to support the vector value type.
1280 */
1281void
1283 OperationPool opPool;
1284
1285 // Has all vector value types (e.g. "v4i32", "v16i8", "v2f16", "v8f32")
1286 // that can be found among all the operands present in the machine.
1287 // Register classes will be defined based on these vector value types.
1288 std::set<TCEString> reqRegClassTypes;
1289
1290 // List all existing vector value types in the machine.
1291 OperationDAGSelector::OperationSet::iterator opnIt;
1292 for (opnIt = allOpNames_.begin(); opnIt != allOpNames_.end(); ++opnIt) {
1293 Operation& op = opPool.operation((*opnIt).c_str());
1294
1295 if (&op == &NullOperation::instance()) {
1296 continue;
1297 }
1298
1299 // Go through every operand of the operation.
1300 for (int i = 1; i <= op.operandCount(); ++i) {
1301 Operand& operand = op.operand(i);
1302
1303 // We are only interested in vector operands, skip otherwise.
1304 if (!operand.isVector()) {
1305 continue;
1306 }
1307
1308 TCEString vtStr = ValueType::valueTypeStr(operand);
1309 if (vRegClasses_.find(vtStr) == vRegClasses_.end()) {
1310 reqRegClassTypes.insert(vtStr);
1311 }
1312
1313 // If operand type is "raw" and vector subword width matches
1314 // float or half float width, list it also.
1315 if (operand.type() == Operand::RAW_DATA &&
1316 (operand.elementWidth() == FP_SUBW_WIDTH ||
1317 operand.elementWidth() == HFP_SUBW_WIDTH)) {
1318
1319 ValueType vt(operand);
1320 vt.isFloat_ = true;
1321 const TCEString floatVtStr = vt.valueTypeStr();
1322
1323 if (vRegClasses_.find(floatVtStr) == vRegClasses_.end()) {
1324 reqRegClassTypes.insert(floatVtStr);
1325 }
1326 }
1327 }
1328 }
1329
1330 // Now we have listed all differend vector value types from the machine.
1331 // Create a register class for every LLVM supported vector value type.
1332
1333 std::set<TCEString>::iterator it;
1334 for (it = reqRegClassTypes.begin(); it != reqRegClassTypes.end(); ++it) {
1335 const TCEString& vtStr = *it;
1336 const ValueType vt(vtStr);
1337
1338 if (vt.isSupportedByLLVM()) {
1339 TCEString name = "V" + Conversion::toString(vt.subwCount_);
1340
1341 if ((vt.isFloat_ && vt.subwWidth_ == FP_SUBW_WIDTH) ||
1342 (vt.isFloat_ && vt.subwWidth_ == HFP_SUBW_WIDTH)) {
1343 name += "F";
1344 } else {
1345 name += "I";
1346 }
1347
1348 name += Conversion::toString(vt.subwWidth_) + "Regs";
1349
1350 RegisterClass newRegClass(vt, name);
1351 vRegClasses_.insert(std::make_pair(vtStr, newRegClass));
1352 } else {
1353 verbose("Warning: RegisterClass not created for type: " + vtStr);
1354 }
1355 }
1356}
1357
1358
1359/**
1360 * Writes 64-bit register definitions to the output stream.
1361 */
1362void
1364
1365 // --- Hardcoded reserved registers. ---
1366 std::string i64regs;
1367 std::string f64regs;
1368 size_t i = 0;
1369
1370 if (mach_.is64bit()) {
1371 // --- Hardcoded reserved registers. ---
1372 writeRegisterDef(o, regs64bit_[0], "SP", "R64", "", RESERVED);
1373 writeRegisterDef(o, regs64bit_[1], "IRES0", "R64", "", RESULT);
1374 writeRegisterDef(o, regs64bit_[2], "FP", "R64", "", RESERVED);
1376 o, regs64bit_[3], "KLUDGE_REGISTER", "R64", "", RESERVED);
1377 i64regs = "SP, IRES0, FP, KLUDGE_REGISTER";
1378
1379 //after the loop, i will have the index of first non-special reg.
1380 for (i = 4;
1381 i < std::min(argRegCount_ + 3, (unsigned int)regs64bit_.size());
1382 i++) {
1383 std::string regName = "A" + Conversion::toString(i);
1384 writeRegisterDef(o, regs64bit_[i], regName, "R64", "", ARGUMENT);
1385 i64regs += ", ";
1386 i64regs += regName;
1387 }
1388 } else {
1389
1390 if (regs64bit_.size() < 1) {
1391 RegInfo reg = { "DUMMY64", 0 };
1392 writeRegisterDef(o, reg, "DUMMY64", "R64", "", RESERVED);
1393 i64regs = "DUMMY64";
1394 }
1395
1396 }
1397
1398 // i already contains the correct starting index.
1399 for (; i < regs64bit_.size(); i++) {
1400 std::string intRegName = "L" + Conversion::toString(i);
1401 if (i != 0)
1402 i64regs += ", ";
1403 i64regs += intRegName;
1404 writeRegisterDef(o, regs64bit_[i], intRegName, "R64", "", GPR);
1405 }
1406
1407 if (mach_.is64bit()) {
1408 // Bypass registers
1409 for (size_t j = 0; j < 256; ++j) {
1410 std::string regName = "BP" + Conversion::toString(j);
1411
1412 o << "def " << regName << " : "
1413 << "R64<\"ByPass_Regs"
1414 << "\", []>, DwarfRegNum<"
1415 << "[" << dregNum_++ << "]>;"
1416 << std::endl;
1417 }
1418
1419 // Bypass register class
1420 o << "def R64_ByPass_Regs : RegisterClass<\"TCE\", [i64,i32,f64,f32,f16], 64, (add ";
1421 for (size_t j = 0; j < 256; ++j) {
1422 std::string regName = "BP" + Conversion::toString(j);
1423
1424 if (j != 0) {
1425 o << ", ";
1426 }
1427
1428 o << regName;
1429 }
1430
1431 o << ")>;" << std::endl;
1432 }
1433
1434 TCEString dataTypes64 = use64bitForFP_ ?
1435 "[i64,f64,f32,f16]" :
1436 "[i64,f64]";
1437
1438 o << std::endl
1439 << "def R64Regs : RegisterClass<\"TCE\", " << dataTypes64
1440 << ", 64, (add " << i64regs << ")> ;"
1441 << std::endl;
1442
1443 o << std::endl
1444 << "def R64IRegs : RegisterClass<\"TCE\", [i64], 64, (add "
1445 << i64regs << ")> ;"
1446 << std::endl;
1447
1448 o << std::endl
1449 << "def R64FPRegs : RegisterClass<\"TCE\", [f32], 64, (add "
1450 << i64regs << ")>;" << std::endl;
1451
1452 o << std::endl
1453 << "def R64HFPRegs : RegisterClass<\"TCE\", [f16], 64, (add "
1454 << i64regs << ")>;" << std::endl;
1455
1456 o << std::endl
1457 << "def R64DFPRegs : RegisterClass<\"TCE\", [f64], 64, (add "
1458 << i64regs << ")>;" << std::endl << std::endl;
1459
1460 if (use64bitForFP_) {
1461 o << "def FPRegs : RegisterClass<\"TCE\", [f32], 64, (add "
1462 << i64regs << ")>;" << std::endl << std::endl;
1463
1464 o << "def HFPRegs : RegisterClass<\"TCE\", [f16], 64, (add "
1465 << i64regs << ")>;" << std::endl << std::endl;
1466 }
1467}
1468
1469
1470/**
1471 * Groups all registers in the machine by register width.
1472 *
1473 * Goes through register files and sorts all real machine registers into
1474 * <Width, vector<Register>> groups. A base class for each Width is also
1475 * created.
1476 */
1477void
1481 std::map<int, std::vector<RegisterInfo>>::iterator it;
1482
1483 // Go through every register file in the machine.
1484 for (int i = 0; i < nav.count(); i++) {
1485 const TTAMachine::RegisterFile* rf = nav.item(i);
1486 assert(rf != NULL);
1487
1488 // Check that the registerfile has both input and output ports.
1489 bool hasInput = false;
1490 bool hasOutput = false;
1491 for (int p = 0; p < rf->portCount(); p++) {
1492 if (rf->port(p)->isInput()) hasInput = true;
1493 if (rf->port(p)->isOutput()) hasOutput = true;
1494 }
1495
1496 if (!hasInput) {
1499
1501 << "Warning: Skipping register file '"
1502 << rf->name()
1503 << "': no input ports."
1504 << std::endl;
1505 }
1506 continue;
1507 }
1508
1509 if (!hasOutput) {
1513 << "Warning Skipping register file '"
1514 << rf->name()
1515 << "': no output ports."
1516 << std::endl;
1517 }
1518 continue;
1519 }
1520
1521 int rfWidth = rf->width();
1522
1523 // If there is no entry for the width of the registers, create one.
1524 if (registers_.find(rfWidth) == registers_.end()) {
1525 registers_.insert(
1526 std::make_pair(rfWidth, std::vector<RegisterInfo>()));
1527 }
1528
1529 it = registers_.find(rfWidth);
1530 std::vector<RegisterInfo>& registers = it->second;
1531
1532 // Skip scalar size registers, they have been listed in TDGen.
1533 if (rfWidth > MAX_SCALAR_WIDTH) {
1534 // Kludge fix: Machines with >32 bit regs but without any vector
1535 // operations generates register info td file with 64 bit register
1536 // definition which are not associated to any register class.
1537 // This triggers assertion in LLVM side.
1538 if (vRegClasses_.empty()) continue;
1539
1540 int lastIdx = rf->size();
1541
1542 bool isTempRegRf = AssocTools::containsKey(tempRegFiles_, rf);
1543 if (isTempRegRf) {
1544 // If the machine is not enough connected,
1545 // preserve last register
1546 // of all register files for routing values.
1547 lastIdx--;
1548 }
1549
1550 // Associate register file's registers with the width.
1551 for (int index = 0; index < lastIdx; ++index) {
1552 TCEString regName(
1553 rf->name() + "_" + Conversion::toString(index));
1554 RegisterInfo reg(regName, rf->name(), index, rfWidth);
1555 registers.push_back(reg);
1556 }
1557 }
1558 }
1559
1561
1562 // TDGen has hardcoded register name definitions, some
1563 // inspection needs to be done to create correct register names.
1564
1565 std::vector<RegisterInfo> regs1bit;
1566 for (size_t i = 0; i < regs1bit_.size(); ++i) {
1567 RegisterInfo reg(
1568 "B" + Conversion::toString(i),
1569 regs1bit_[i].rf,
1570 regs1bit_[i].idx,
1571 1);
1572 regs1bit.push_back(reg);
1573 }
1574 registers_[1] = regs1bit;
1575
1576 /// @todo Apparently TDGen does not write information of 8 bit
1577 /// registers -> can't add them.
1578
1579 std::vector<RegisterInfo> regs16bit;
1580 for (size_t i = 0; i < regs16bit_.size(); ++i) {
1581 RegisterInfo reg(
1582 "H" + Conversion::toString(i),
1583 regs16bit_[i].rf,
1584 regs16bit_[i].idx,
1585 16);
1586
1587 if (i == 0) {
1588 reg.regName_ = "HIRES0";
1589 }
1590
1591 regs16bit.push_back(reg);
1592 }
1593 registers_[16] = regs16bit;
1594
1595 std::vector<RegisterInfo> regs32bit;
1596 for (size_t i = 0; i < regs32bit_.size(); ++i) {
1597 RegisterInfo reg(
1598 "I" + Conversion::toString(i),
1599 regs32bit_[i].rf,
1600 regs32bit_[i].idx,
1601 32);
1602
1603
1604 if (!mach_.is64bit()) {
1605 if (i == 0) {
1606 reg.regName_ = "SP";
1607 } else if (i == 1) {
1608 reg.regName_ = "IRES0";
1609 } else if (i == 2) {
1610 reg.regName_ = "FP";
1611 } else if (i == 3) {
1612 reg.regName_ = "KLUDGE_REGISTER";
1613 } else if (i < argRegCount_ + 3) {
1614 reg.regName_ = "A" + Conversion::toString(i);
1615 }
1616 }
1617 regs32bit.push_back(reg);
1618 }
1619 registers_[32] = regs32bit;
1620
1621 std::vector<RegisterInfo> regs64bit;
1622 for (size_t i = 0; i < regs64bit_.size(); ++i) {
1623 RegisterInfo reg(
1624 "L" + Conversion::toString(i),
1625 regs64bit_[i].rf,
1626 regs64bit_[i].idx,
1627 64);
1628
1629 if (mach_.is64bit()) {
1630 if (i == 0) {
1631 reg.regName_ = "SP";
1632 } else if (i == 1) {
1633 reg.regName_ = "IRES0";
1634 } else if (i == 2) {
1635 reg.regName_ = "FP";
1636 } else if (i == 3) {
1637 reg.regName_ = "KLUDGE_REGISTER";
1638 } else if (i < argRegCount_ + 3) {
1639 reg.regName_ = "A" + Conversion::toString(i);
1640 }
1641 }
1642 regs64bit.push_back(reg);
1643 }
1644 registers_[64] = regs64bit;
1645
1646 // Create base classes for different register widths.
1647 for (it = registers_.begin(); it != registers_.end(); ++it) {
1648 int width = it->first;
1649 if (width > MAX_SCALAR_WIDTH) {
1650 baseClasses_.insert(
1651 std::make_pair(width, "VR" + Conversion::toString(width)));
1652 } else {
1653 baseClasses_.insert(
1654 std::make_pair(width, "R" + Conversion::toString(width)));
1655 }
1656 }
1657}
1658
1659/**
1660 * Sets registers to use round robin order in register allocation.
1661 *
1662 * Starting from register index number 0, all same width registers having
1663 * the same index number are pushed to a vector. Then, index is increased
1664 * by one and same action is performed, index increased etc., until all
1665 * registers of same width are pushed to the vector. Then, the vector is
1666 * used to replace old register order.
1667 *
1668 * For example, two register files R64_1 (register indices 0, 1, 2 and 3)
1669 * and R64_2 (register indices 0, 1) are ordered as:
1670 * R64_1(0), R64_2(0), R64_1(1), R64_2(1), R64_1(2), R64_1(3), and LLVM
1671 * register allocator will use this order to allocate the registers.
1672 */
1673void
1675 std::vector<RegisterInfo> roundRobinOrder;
1676
1677 // Loop through every different group of register widths.
1678 std::map<int, std::vector<RegisterInfo>>::iterator it;
1679 for (it = registers_.begin(); it != registers_.end(); ++it) {
1680 roundRobinOrder.clear();
1681 std::vector<RegisterInfo>& registers = it->second;
1682
1683 unsigned i = 0;
1684 unsigned idx = 0;
1685
1686 // Loop until all registers of same width are reordered.
1687 while (roundRobinOrder.size() != registers.size()) {
1688 RegisterInfo& info = registers[i];
1689 if (info.regIndex_ == idx) {
1690 roundRobinOrder.push_back(info);
1691 }
1692
1693 if (i == registers.size() - 1) {
1694 i = 0;
1695 ++idx;
1696 } else {
1697 ++i;
1698 }
1699 }
1700
1701 registers = roundRobinOrder;
1702 }
1703}
1704
1705/**
1706 * Attaches proper register groups to register files.
1707 */
1708void
1710 std::map<TCEString, RegisterClass>::iterator rcIt;
1711 for (rcIt = vRegClasses_.begin(); rcIt != vRegClasses_.end(); ++rcIt) {
1712 RegisterClass& regClass = rcIt->second;
1713
1714 // Go through all register groups (they are in ascending order by
1715 // width -> starts from the smallest width always towards wider ones).
1716 std::map<int, std::vector<RegisterInfo>>::iterator regsIt =
1717 registers_.begin();
1718
1719 bool found = false;
1720 while (!found && regsIt != registers_.end()) {
1721 int regsWidth = regsIt->first;
1722 size_t amountOfRegs = (regsIt->second).size();
1723
1724 // If can find a group of registers which satisfies the
1725 // register class width requirement, choose those registers.
1726 if (regsWidth >= regClass.valueType().width() &&
1727 amountOfRegs > 0) {
1728 const std::vector<RegisterInfo>& regs = regsIt->second;
1729 regClass.addRegisters(regs);
1730 found = true;
1731 }
1732
1733 ++regsIt;
1734 }
1735
1736 // If bigger register exploitation is desired, append all the rest
1737 // of the registers, because there are only wider registers left.
1739 while (regsIt != registers_.end()) {
1740 const std::vector<RegisterInfo>& biggerRegs = regsIt->second;
1741 regClass.addRegisters(biggerRegs);
1742 ++regsIt;
1743 }
1744 }
1745 }
1746}
1747
1748/**
1749 * Checks if operation has operands of raw type.
1750 *
1751 * @param op Operation to be checked.
1752 * @return True, if operation has at least one operand of raw type.
1753 */
1754bool
1756 for (int i = 1; i <= op.operandCount(); ++i) {
1757 const Operand& operand = op.operand(i);
1758 if (operand.type() == Operand::RAW_DATA && operand.isVector()) {
1759 return true;
1760 }
1761 }
1762 return false;
1763}
1764
1765/**
1766 * Returns subword width of vector operands of "raw" type.
1767 *
1768 * @note This function chooses the subword width based on subword width
1769 * of the WIDEST "raw" data operand that can be found from the operation,
1770 * since that approach works for current SIMD operation definitions.
1771 * If this approach doesn't work for your operation, modify the function
1772 * properly to fulfil your needs.
1773 *
1774 * @param op Operation that has raw operands.
1775 * @return Subword width of the raw vector operands.
1776 */
1777int
1779 int widestWidth = -1;
1780 int widestRawOperandIndex = -1;
1781 for (int i = 1; i <= op.operandCount(); ++i) {
1782 const Operand& operand = op.operand(i);
1783 if (operand.type() == Operand::RAW_DATA && operand.isVector()) {
1784 if (operand.width() > widestWidth) {
1785 widestWidth = operand.width();
1786 widestRawOperandIndex = i;
1787 }
1788 }
1789 }
1790
1791 if (widestRawOperandIndex >= 0) {
1792 return op.operand(widestRawOperandIndex).elementWidth();
1793 }
1794
1795 assert(false && "Invalid input operation.");
1796}
1797
1798/**
1799 * Checks if all operands of the operation have a supporting register class.
1800 *
1801 * @param op Operation whose operands will be checked.
1802 * @return True, if all operands are supported by register classes.
1803 */
1804bool
1806 for (int i = 1; i <= op.operandCount(); ++i) {
1807 const Operand& operand = op.operand(i);
1808
1809 if (operand.isVector()) {
1810 TCEString vtStr = ValueType::valueTypeStr(operand);
1811 if (vRegClasses_.find(vtStr) == vRegClasses_.end()) {
1812 return false;
1813 }
1814 }
1815 }
1816
1817 return true;
1818}
1819
1820/**
1821 * Checks if the ValueType has a supporting register class.
1822 *
1823 * @param vt ValueType to be checked.
1824 * @return True, if the value type is supported by a register class.
1825 */
1826bool
1828 if (vRegClasses_.find(vt.valueTypeStr()) == vRegClasses_.end()) {
1829 return false;
1830 }
1831
1832 return true;
1833}
1834
1835/**
1836 * Returns the name of the vector class that supports given operand.
1837 *
1838 * @param operand Checked if any register class supports value type of this.
1839 * @return Name of the register class that supports operand's value type.
1840 */
1843 std::map<TCEString, RegisterClass>::const_iterator it =
1845
1846 if (it == vRegClasses_.end()) {
1847 // Shouldn't get here because any operation whose operands are not
1848 // supported will not get created.
1849 assert(false);
1850 }
1851
1852 const RegisterClass& regClass = it->second;
1853 return regClass.name();
1854}
1855
1856/**
1857 * Prints debugging information if verbose switch is used.
1858 *
1859 * @param msg Debug message.
1860 */
1861void
1862TDGen::verbose(const TCEString& msg) const {
1864 Application::logStream() << msg << endl;
1865 }
1866}
1867
1868/**
1869 * Writes a pattern fragment definition.
1870 *
1871 * @param origPat Pattern that instruction selector should replace.
1872 * @param replacerPat Pattern that will replace the original pattern.
1873 */
1874void
1876 std::ostream& o,
1877 const TCEString& origPat,
1878 const TCEString& replacerPat) const {
1879 o << "def : Pat<(" << origPat << "), (" << replacerPat << ")>;" << endl;
1880}
1881
1882/**
1883 * Writes operation definition using given operand types.
1884 *
1885 * Changes the operands to match the provided ones, after which a definition
1886 * is written. Finally, original operands are restored.
1887 *
1888 * @param o Output stream.
1889 * @param op Operation used to create new operation definitions.
1890 * @param skipPattern If true, operation pattern writing is skipped.
1891 * @param inputs Input operand types for the new operation.
1892 * @param outputs Output operand types for the new operation.
1893 * @param instrSuffix Optional suffix that will be added to instruction name.
1894 */
1895void
1897 std::ostream& o,
1898 Operation& op,
1899 bool skipPattern,
1900 std::vector<ValueType> inputs,
1901 std::vector<ValueType> outputs,
1902 TCEString instrSuffix) {
1903 assert(
1904 inputs.size() == static_cast<size_t>(op.numberOfInputs()) &&
1905 "Given input operand count doesn't match operation's count.");
1906 assert(
1907 outputs.size() == static_cast<size_t>(op.numberOfOutputs()) &&
1908 "Given output operand count doesn't match operation's count.");
1909
1910 std::vector<ValueType> oldInputs;
1911 std::vector<ValueType> oldOutputs;
1912
1913 // Change operands to match the provided ones.
1914 for (int i = 0; i < op.numberOfInputs(); ++i) {
1915 Operand& input = op.input(i);
1916 oldInputs.push_back(ValueType(input));
1917
1918 ValueType vt = inputs[i];
1919 input.setType(vt.operandType());
1920 input.setElementWidth(vt.subwWidth_);
1921 input.setElementCount(vt.subwCount_);
1922 }
1923
1924 for (int i = 0; i < op.numberOfOutputs(); ++i) {
1925 Operand& output = op.output(i);
1926 oldOutputs.push_back(ValueType(output));
1927
1928 ValueType vt = outputs[i];
1929 output.setType(vt.operandType());
1930 output.setElementWidth(vt.subwWidth_);
1931 output.setElementCount(vt.subwCount_);
1932 }
1933
1934 // Write new operation definition.
1935 TCEString types = createDefaultOperandTypeString(op) + instrSuffix;
1936 writeVectorOperationDef(o, op, types, "", skipPattern);
1937
1938 // Restore old operands.
1939 for (int i = 0; i < op.numberOfInputs(); ++i) {
1940 Operand& input = op.input(i);
1941
1942 ValueType vt = oldInputs[i];
1943 input.setType(vt.operandType());
1944 input.setElementWidth(vt.subwWidth_);
1945 input.setElementCount(vt.subwCount_);
1946 }
1947
1948 for (int i = 0; i < op.numberOfOutputs(); ++i) {
1949 Operand& output = op.output(i);
1950
1951 ValueType vt = oldOutputs[i];
1952 output.setType(vt.operandType());
1953 output.setElementWidth(vt.subwWidth_);
1954 output.setElementCount(vt.subwCount_);
1955 }
1956}
1957
1958/**
1959 * Checks if the given operation is a vector load memory operation.
1960 *
1961 * @param op Operation which is checked.
1962 * @return True, if operation is a vector load memory operation.
1963 */
1964bool
1966 abortWithError("WiP");
1967 return false;
1968}
1969
1970/**
1971 * Checks if the given operation is a vector store memory operation.
1972 *
1973 * @param op Operation which is checked.
1974 * @return True, if operation is a vector store memory operation.
1975 */
1976bool
1978 abortWithError("WiP");
1979 return false;
1980}
1981
1982bool
1984 abortWithError("WiP");
1985 return false;
1986}
1987
1988/**
1989 * Checks if the given operation is a bitwise operation.
1990 *
1991 * @param op Operation which is checked.
1992 * @return True, if operation is a bitwise operation.
1993 */
1994bool
1996 abortWithError("WiP");
1997 return false;
1998}
1999
2000
2001/**
2002 * Writes register class for registers usable as guard.
2003 *
2004 * Call this after all regular register definitions are written (after all
2005 * calls to writeRegisterDef());
2006 */
2007void
2009
2010 int bits = mach_.is64bit() ? 64 : 32;
2011 o << std::endl
2012 << "// #################################" << std::endl
2013 << "// Register class definitions for guards" << std::endl;
2014
2015 if (llvmGuardRegs_.empty()) {
2016 o << "// No guard registers in this machine" << std::endl;
2017 RegInfo reg = {"noGuardReg", 0};
2018 std::string name = "NOGUARD";
2019 writeRegisterDef(o, reg, name, "R1", "", RESERVED);
2020 o << "def " << guardRegTemplateName
2021 << "Regs : RegisterClass<\"TCE\", [i1], " << bits << ", (add "
2022 << name << ")>;" << std::endl;
2023 return;
2024 }
2025
2026 o << "def " << guardRegTemplateName
2027 << "Regs : RegisterClass<\"TCE\", [i1], " << bits << ", (add ";
2028 bool firstItem = true;
2029 for (auto& regDef : llvmGuardRegs_) {
2030 if (firstItem) {
2031 o << regDef;
2032 firstItem = false;
2033 continue;
2034 }
2035 o << ", " << regDef;
2036 }
2037 o << ")> {" << std::endl;
2038 o << " let Size=" << bits << ";" << std::endl;
2039 o << "}" << std::endl;
2040 o << "// #################################" << std::endl << std::endl;
2041}
2042
2043/**
2044 * Writes base class definitions to the .td file.
2045 */
2046void
2048 o << endl
2049 << "// #################################" << endl
2050 << "// Vector register base class definitions" << endl;
2051
2052 std::map<int, TCEString>::const_iterator bcIt;
2053 for (bcIt = baseClasses_.begin(); bcIt != baseClasses_.end(); ++bcIt) {
2054 int width = bcIt->first;
2055
2056 if (width > MAX_SCALAR_WIDTH) {
2057 TCEString baseClassName = bcIt->second;
2058 o << "class " << baseClassName
2059 << "<string n, list<Register> aliases> : "
2060 << "TCEVectorReg<n, aliases> {}" << endl;
2061 }
2062 }
2063 o << "// #################################" << endl;
2064}
2065
2066/**
2067 * Writes register definitions to the .td file.
2068 */
2069void
2071 o << endl
2072 << "// #################################" << endl
2073 << "// Register name definitions for vector registers" << endl;
2074
2075 std::set<TCEString> declaredRegNames;
2076
2077 std::map<int, std::vector<RegisterInfo>>::const_iterator it;
2078 for (it = registers_.begin(); it != registers_.end(); ++it) {
2079 int regsWidth = it->first;
2080
2081 const std::vector<RegisterInfo>& regs = it->second;
2082 TCEString baseClass = baseClasses_.find(regsWidth)->second;
2083
2084 for (size_t i = 0; i < regs.size(); ++i) {
2085 // Don't declare <=32b registers again, it has been done in TDGen.
2086 if (regsWidth > MAX_SCALAR_WIDTH) {
2087 RegisterInfo reg = regs[i];
2088 RegInfo oldRegInfo = {reg.regFileName_, reg.regIndex_};
2090 o, oldRegInfo, reg.regName_, baseClass, "", RESERVED);
2091 declaredRegNames.insert(reg.regName_);
2092 }
2093 }
2094 }
2095 o << "// #################################" << endl;
2096}
2097
2098/**
2099 * Writes register class definitions to the .td file.
2100 */
2101void
2103 o << endl
2104 << "// #################################" << endl
2105 << "// Register class definitions for vector registers" << endl;
2106
2107 std::map<TCEString, RegisterClass>::const_iterator it;
2108 for (it = vRegClasses_.begin(); it != vRegClasses_.end(); ++it) {
2109 const TCEString& vtStr = it->first;
2110 const RegisterClass& regClass = it->second;
2111
2112 if (regClass.numberOfRegisters() == 0) {
2113 std::string msg =
2114 std::string("The machine is missing registers for ") +
2115 regClass.valueType().valueTypeStr() + " operands" +
2116 " required by some operation(s).";
2117
2118 std::cerr << "Error: Illegal machine: " << msg << std::endl;
2120 }
2121
2122 o << "def " << regClass.name() << " : "
2123 << "RegisterClass<\"TCE\", "
2124 << "[" << vtStr << "], " << regClass.alignment() << ", (add ";
2125
2126 // Add registers to the register class.
2127 for (size_t i = 0; i < regClass.numberOfRegisters(); ++i) {
2128 const RegisterInfo& reg = regClass.registerInfo(i);
2129 o << reg.regName_;
2130
2131 if (i != regClass.numberOfRegisters() - 1) {
2132 o << ", ";
2133 }
2134 }
2135 o << ")> ";
2136
2137 // Register classes below 8 bit of total width need to be set as
2138 // "8 bit of size" so that when they are spilled to stack, the
2139 // byte size of the register class is at least 1.
2140 if (regClass.valueType().width() < 8) {
2141 o << "{" << endl << " let Size=8;" << endl << "}" << endl;
2142 } else {
2143 o << ";" << endl;
2144 }
2145 }
2146
2147 o << "// #################################" << endl;
2148}
2149
2150/**
2151 * Writes needed defitinion(s) of the vector operation to the .td file.
2152 *
2153 * Creates 4 differend instructions of the operation at most:
2154 * - Integer version (register)
2155 * - Integer version (immediate)
2156 * - Float/half float version (register)
2157 * - Float/half float version (immediate)
2158 *
2159 * @param o Output stream to the .td file.
2160 * @param op Vector operation of which the definitions will be created.
2161 * @param skipPattern True, if skip pattern creation.
2162 */
2163void
2165 abortWithError("WiP");
2166}
2167
2168/**
2169 * Writes instruction of the vector operation to the .td file.
2170 *
2171 * Creates register version and possibly an immediate version of the
2172 * vector operation in case there are any scalar operands.
2173 *
2174 * @param o Output stream to the file.
2175 * @param op Operation to be written as an instruction to the .td file.
2176 * @param valueTypes Operand value type identifier characters.
2177 * @param attributes Operation attributes.
2178 * @param skipPattern True, if skip pattern creation.
2179 */
2180void
2182 std::ostream& o, Operation& op, TCEString valueTypes,
2183 const TCEString& attributes, bool skipPattern) {
2184 // Make sure operation's operands are fully supported by
2185 // vector register classes.
2186 if (!hasRegisterClassSupport(op)) {
2187 verbose(
2188 "Warning: " + op.name() + valueTypes +
2189 " was not created due to unsupported operands.");
2190 return;
2191 }
2192
2193 // Write register version of the operation.
2194 TDGen::writeOperationDef(o, op, valueTypes, attributes, skipPattern);
2195
2196 // Information of some operations is needed later, save it if needed.
2197 saveAdditionalVectorOperationInfo(op, valueTypes, true);
2198
2199 // Create the same instruction with immediate inputs if there are
2200 // any input operands that are scalars.
2201 bool scalarsFound = false;
2202 for (int i = op.numberOfOutputs(); i < op.operandCount(); ++i) {
2203 char& c = valueTypes[i];
2204 switch (c) {
2205 case OT_REG_BOOL:
2206 c = OT_IMM_BOOL;
2207 scalarsFound = true;
2208 break;
2209 case OT_REG_INT:
2210 c = OT_IMM_INT;
2211 scalarsFound = true;
2212 break;
2213 case OT_REG_FP:
2214 c = OT_IMM_FP;
2215 scalarsFound = true;
2216 break;
2217 case OT_REG_HFP:
2218 c = OT_IMM_HFP;
2219 scalarsFound = true;
2220 break;
2221 default:
2222 continue;
2223 }
2224 }
2225
2226 if (scalarsFound) {
2227 // Write immediate version of the operation.
2228 TDGen::writeOperationDef(o, op, valueTypes, attributes, skipPattern);
2229
2230 // Information of some immediate versions are needed also.
2231 saveAdditionalVectorOperationInfo(op, valueTypes, false);
2232 }
2233}
2234
2235/**
2236 * Saves information of some operations.
2237 *
2238 * Additional information of some operations is needed later, and thus,
2239 * they need to be saved for later reference.
2240 *
2241 * @param op Vector operation.
2242 * @param valueTypes Operand value type identifier characters.
2243 * @param isRegisterOp If false, operation has immediate operands.
2244 */
2245void
2247 const Operation&, const TCEString&, bool) {
2248 abortWithError("WiP");
2249}
2250
2251/**
2252 * Writes instruction definitions for memory vector operations.
2253 *
2254 * Subword aligned LDQ/LDH/LDW/STQ/STH/STQ vector operations can be passed
2255 * directly to writing vector operation definitions, but vector aligned
2256 * LOAD and STORE operations can be used for several different vector types
2257 * of the same width, thus, all the different vector types need to be
2258 * covered and separate memory instruction have to be made for them.
2259 */
2260void
2262 std::ostream&, Operation&, bool) {
2263 abortWithError("WiP");
2264}
2265
2266/**
2267 * Writes MOV instructions between vector register classes.
2268 */
2269void
2271 o << endl
2272 << "// Vector register->register move definitions." << endl
2273 << "let isAsCheapAsAMove = 1 in {" << endl;
2274
2275 std::map<TCEString, RegisterClass>::const_iterator it;
2276 for (it = vRegClasses_.begin(); it != vRegClasses_.end(); ++it) {
2277 const RegisterClass& regClass = it->second;
2278
2279 const TCEString opcode = "MOV" + regClass.name();
2280 const TCEString vtStr = regClass.valueType().valueTypeStr();
2281
2282 const TCEString outs = "(outs " + regClass.name() + ":$dst), ";
2283 const TCEString ins = "(ins " + regClass.name() + ":$src), ";
2284 const TCEString insPred =
2285 "(ins GuardRegs:$pred, " + regClass.name() + ":$src), ";
2286 const TCEString asmOp = "\"$src -> $dst;\", []";
2287
2288 o << "def " << opcode << " : "
2289 << "InstTCE<" << outs << ins << asmOp << ">;" << endl;
2290
2291 opNames_[opcode] = opcode;
2292 movOperations_.insert(opcode);
2293
2295 o << "def PRED_TRUE_" << opcode << " : "
2296 << "InstTCE<" << outs << insPred << asmOp << ">;" << endl;
2297
2298 o << "def PRED_FALSE_" << opcode << " : "
2299 << "InstTCE<" << outs << insPred << asmOp << ">;" << endl;
2300
2301 opNames_["PRED_TRUE_" + opcode] = "?" + opcode;
2302 opNames_["PRED_FALSE_" + opcode] = "!" + opcode;
2303 truePredOps_[opcode] = "PRED_TRUE_" + opcode;
2304 falsePredOps_[opcode] = "PRED_TRUE_" + opcode;
2305
2306 movOperations_.insert("PRED_TRUE_" + opcode);
2307 movOperations_.insert("PRED_FALSE_" + opcode);
2308 }
2309 }
2310
2311 o << "}" << endl;
2312}
2313
2314/**
2315 * Writes truncstore patterns for vector value types.
2316 */
2317void
2318TDGen::writeVectorTruncStoreDefs(std::ostream& o) const {
2319 o << endl << "// Vector truncstore definitions, needed below." << endl;
2320
2321 // Create truncstore definitions for vector value types, there has to
2322 // exist store operations for the same value type that the TRUNC
2323 // operation has. For example, in order to create truncstore using
2324 // TRUNCWH16X4, there has to be store operations in the machine that
2325 // supports storing v4i16 value type.
2326
2327 std::map<TCEString, RegisterClass>::const_iterator rcIt;
2328 for (rcIt = vRegClasses_.begin(); rcIt != vRegClasses_.end(); ++rcIt) {
2329 o << "def truncstore" << rcIt->first << " : "
2330 << "PatFrag<(ops node:$val, node:$ptr),"
2331 << "(truncstore node:$val, node:$ptr), "
2332 << "[{return cast<StoreSDNode>(N)->getMemoryVT() == "
2333 << "MVT::" << rcIt->first << ";}]>;" << endl;
2334 }
2335 // Create patterns which will replace "truncstore" pattern with separate
2336 // TRUNC and then STORE operations.
2337
2338 o << endl << "// Pattern definitions for truncstores." << endl;
2339 std::vector<std::pair<const Operation*, TCEString>>::const_iterator it;
2340 for (it = truncOperations_.begin(); it != truncOperations_.end(); ++it) {
2341 const TCEString& truncInstr = it->second;
2342 const TCEString& vtFromStr =
2343 ValueType::valueTypeStr(it->first->input(0));
2344 const TCEString targetVtStr =
2345 ValueType::valueTypeStr(it->first->output(0));
2346
2347 std::map<TCEString, InstructionInfo>::const_iterator regStoreIt =
2348 registerStores_.find(targetVtStr);
2349
2350 // Use register version of store operations.
2351 if (regStoreIt != registerStores_.end()) {
2352 const TCEString& regStoreInstr = (regStoreIt->second).instrName_;
2353 const TCEString originalPattern = "truncstore" + targetVtStr +
2354 " " + vtFromStr +
2355 ":$op2, ADDRrr:$op1";
2356 const RegisterClass& regClass =
2357 vRegClasses_.find(vtFromStr)->second;
2358 const TCEString replacerPattern =
2359 regStoreInstr + " ADDRrr:$op1, (" + truncInstr + " " +
2360 regClass.name() + ":$op2)";
2361
2362 writePatternReplacement(o, originalPattern, replacerPattern);
2363 }
2364
2365 std::map<TCEString, InstructionInfo>::const_iterator immStoreIt =
2366 immediateStores_.find(targetVtStr);
2367
2368 // Use immediate version of store operations.
2369 if (immStoreIt != immediateStores_.end()) {
2370 const TCEString& immStoreInstr = (immStoreIt->second).instrName_;
2371 const TCEString originalPattern = "truncstore" + targetVtStr +
2372 " " + vtFromStr +
2373 ":$op2, ADDRri:$op1";
2374 const RegisterClass& regClass =
2375 vRegClasses_.find(vtFromStr)->second;
2376 const TCEString replacerPattern =
2377 immStoreInstr + " ADDRri:$op1, (" + truncInstr + " " +
2378 regClass.name() + ":$op2)";
2379 writePatternReplacement(o, originalPattern, replacerPattern);
2380 }
2381 }
2382}
2383
2384/**
2385 * Writes scalar_to_vector patterns for vector value types.
2386 */
2387void
2388TDGen::writeScalarToVectorDefs(std::ostream& o) const {
2389 o << endl << "// Scalar to vector definitions." << endl;
2390 std::map<TCEString, TCEString>::const_iterator it;
2391 for (it = vbcastOperations_.begin(); it != vbcastOperations_.end();
2392 ++it) {
2393 const TCEString& vtStr = it->first;
2394 const TCEString& vbcastInstr = it->second;
2395
2396 ValueType scalarVt(vtStr);
2397 scalarVt.subwCount_ = 1; // Change vector type to scalar.
2398 TCEString scalarVtStr = scalarVt.valueTypeStr();
2399
2400 /// @todo Add i8 and i16 subword support once those types have
2401 /// RegisterClass support. For now, just skip generation for them.
2402 if (scalarVtStr == "f16" || scalarVtStr == "f32" ||
2403 scalarVtStr == "i32") {
2404 TCEString originalPattern =
2405 vtStr + " (scalar_to_vector " + scalarVtStr + ":$in)";
2406 TCEString replacerPattern =
2407 vbcastInstr + " " + scalarVtStr + ":$in";
2408
2409 writePatternReplacement(o, originalPattern, replacerPattern);
2410 }
2411 }
2412}
2413
2414/**
2415 * Writes bit conversion patterns.
2416 */
2417void
2418TDGen::writeVectorBitConversions(std::ostream& o) const {
2419 o << endl << "// Bit conversions between vector types." << endl;
2420
2421 std::map<TCEString, RegisterClass>::const_iterator it1;
2422 for (it1 = vRegClasses_.begin(); it1 != vRegClasses_.end(); ++it1) {
2423 const TCEString& vtStr1 = it1->first;
2424 const RegisterClass& regClass1 = it1->second;
2425
2426 std::map<TCEString, RegisterClass>::const_iterator it2;
2427 for (it2 = vRegClasses_.begin(); it2 != vRegClasses_.end(); ++it2) {
2428 const TCEString& vtStr2 = it2->first;
2429 const RegisterClass& regClass2 = it2->second;
2430 if (regClass1.valueType().width() !=
2431 regClass2.valueType().width() ||
2432 vtStr1 == vtStr2) {
2433 continue;
2434 }
2435 const TCEString originalPattern = vtStr2 + " (bitconvert (" +
2436 vtStr1 + " " +
2437 regClass1.name() + ":$src))";
2438 const TCEString replacerPattern =
2439 vtStr2 + " " + regClass2.name() + ":$src";
2440 writePatternReplacement(o, originalPattern, replacerPattern);
2441 }
2442 }
2443
2444 o << endl << "// Bit conversions to/from i32." << endl;
2445
2446 // Write i32 -> same size vector type bit conversions.
2447 std::map<TCEString, RegisterClass>::const_iterator it;
2448 for (it = vRegClasses_.begin(); it != vRegClasses_.end(); ++it) {
2449 const TCEString& vtStr = it->first;
2450 const RegisterClass& regClass = it->second;
2451
2452 if (regClass.valueType().width() == 32 && vtStr != "i32") {
2453 TCEString originalPattern = "i32 (bitconvert (" + vtStr + " " +
2454 regClass.name() + ":$src))";
2455 TCEString replacerPattern = "i32 R32IRegs:$src";
2456 writePatternReplacement(o, originalPattern, replacerPattern);
2457
2458 originalPattern = vtStr + " (bitconvert (i32 R32IRegs:$src))";
2459 replacerPattern = vtStr + " " + regClass.name() + ":$src";
2460 writePatternReplacement(o, originalPattern, replacerPattern);
2461 }
2462 }
2463}
2464
2465/**
2466 * This function writes scalar operation exploitations.
2467 *
2468 * Some scalar operations can be exploited to execute vector operations.
2469 * For instance, bitwise logical operations are same for any operand width.
2470 * A 32-bit scalar XOR operation can execute bitwise exclusive OR operation
2471 * for v32i1, v4i8 and v2i16 vector operands similarly as it does for i32
2472 * type.
2473 */
2474void
2476 o << endl
2477 << endl
2478 << "// Scalar operations exploited to execute small vector operations."
2479 << endl;
2480
2481 // Use minimal architecture NOT/AND/IOR/XOR 32-bit operations to execute
2482 // bitwise vector operations with operands of 32 bits or lower width.
2483 OperationPool opPool;
2484
2485 std::vector<Operation*> scalarBitwiseOps;
2486 scalarBitwiseOps.push_back(&opPool.operation("NOT"));
2487 scalarBitwiseOps.push_back(&opPool.operation("AND"));
2488 scalarBitwiseOps.push_back(&opPool.operation("IOR"));
2489 scalarBitwiseOps.push_back(&opPool.operation("XOR"));
2490 scalarBitwiseOps.push_back(&opPool.operation("NOT64"));
2491 scalarBitwiseOps.push_back(&opPool.operation("AND64"));
2492 scalarBitwiseOps.push_back(&opPool.operation("IOR64"));
2493 scalarBitwiseOps.push_back(&opPool.operation("XOR64"));
2494
2495
2496 for (size_t opI = 0; opI < scalarBitwiseOps.size(); ++opI) {
2497 Operation& op = *scalarBitwiseOps[opI];
2498 if (&op == &NullOperation::instance() ||
2499 !mach_.hasOperation(op.name())) {
2500 continue;
2501 }
2502
2503 int width = 2;
2504
2505 while (width <= op.output(0).width()) {
2506 // Get vector value types for the current width, e.g v4i8, v2i16
2507 // and v32i1 value types for width 32.
2508 std::vector<ValueType> intVecVts =
2509 ValueType::vectorTypesOfWidth(width, true);
2510
2511 for (size_t i = 0; i < intVecVts.size(); ++i) {
2512 ValueType& vecVt = intVecVts[i];
2513 const TCEString vecVtStr = vecVt.valueTypeStr();
2514
2515 if (hasRegisterClassSupport(vecVt)) {
2516 std::vector<ValueType> inputs;
2517 std::vector<ValueType> outputs;
2518
2519 for (int i = 0; i < op.numberOfInputs(); ++i) {
2520 inputs.push_back(vecVt);
2521 }
2522 for (int i = 0; i < op.numberOfOutputs(); ++i) {
2523 outputs.push_back(vecVt);
2524 }
2525
2527 o, op, false, inputs, outputs, vecVtStr);
2528 }
2529 }
2530
2531 width *= 2;
2532 }
2533 }
2534
2535 // Use LDQ/LDH/LDW and STQ/STH/STW operations to create memory access
2536 // operations for vector operands of 32-bit or lower width.
2537 int memDataOpndWidth = 2;
2538
2539 const char* defaultType = mach_.is64bit() ? "i64" : "i32";
2540
2541 while (memDataOpndWidth <= MAX_SCALAR_WIDTH) {
2542 std::vector<ValueType> vecVts =
2543 ValueType::vectorTypesOfWidth(memDataOpndWidth);
2544
2545 for (size_t i = 0; i < vecVts.size(); ++i) {
2546 const ValueType& dataOpndVt = vecVts[i];
2547 const TCEString dataOpndVtStr = dataOpndVt.valueTypeStr();
2548
2549 if (hasRegisterClassSupport(dataOpndVt)) {
2550 Operation* op = NULL;
2551 if (memDataOpndWidth <= 8) {
2552 if (littleEndian_) {
2553 op = &opPool.operation("LD8");
2554 } else {
2555 op = &opPool.operation("LDQ");
2556 }
2557 } else if (memDataOpndWidth <= 16) {
2558 if (littleEndian_) {
2559 op = &opPool.operation("LD16");
2560 } else {
2561 op = &opPool.operation("LDH");
2562 }
2563 } else if (memDataOpndWidth <= 32){
2564 if (littleEndian_) {
2565 op = &opPool.operation("LD32");
2566 } else {
2567 op = &opPool.operation("LDW");
2568 }
2569 } else {
2570 if (littleEndian_) {
2571 op = &opPool.operation("LD64");
2572 } else {
2573 op = &opPool.operation("LDD");
2574 std::cerr << "Warning: SIMD support with "
2575 << "big-endian adf is deprecated" << std::endl;
2576 }
2577 }
2578
2579 std::vector<ValueType> inputs;
2580 std::vector<ValueType> outputs;
2581
2582 // Address operand 32 or 64 bits
2583 inputs.push_back(ValueType(defaultType));
2584 // Data operand.
2585 outputs.push_back(dataOpndVt);
2586
2588 o, *op, false, inputs, outputs, dataOpndVtStr);
2589 }
2590 }
2591
2592 for (size_t i = 0; i< vecVts.size(); ++i) {
2593 const ValueType& dataOpndVt = vecVts[i];
2594 const TCEString dataOpndVtStr = dataOpndVt.valueTypeStr();
2595
2596 if (hasRegisterClassSupport(dataOpndVt)) {
2597 Operation* op = NULL;
2598 if (memDataOpndWidth <= 8) {
2599 if (littleEndian_) {
2600 op = &opPool.operation("ST8");
2601 } else {
2602 op = &opPool.operation("STQ");
2603 }
2604 } else if (memDataOpndWidth <= 16) {
2605 if (littleEndian_) {
2606 op = &opPool.operation("ST16");
2607 } else {
2608 op = &opPool.operation("STH");
2609 }
2610 } else if (memDataOpndWidth <= 32) {
2611 if (littleEndian_) {
2612 op = &opPool.operation("ST32");
2613 } else {
2614 op = &opPool.operation("STW");
2615 }
2616 } else {
2617 if (littleEndian_) {
2618 op = &opPool.operation("ST64");
2619 } else {
2620 op = &opPool.operation("STD");
2621 std::cerr << "Warning: SIMD support with "
2622 << "big-endian adf is deprecated" << std::endl;
2623 }
2624 }
2625
2626 std::vector<ValueType> inputs;
2627 std::vector<ValueType> outputs;
2628
2629 // Address operand 32 or 64 bits.
2630 inputs.push_back(ValueType(defaultType));
2631 inputs.push_back(dataOpndVt);
2632 // There is no output operands for store.
2633
2635 o, *op, false, inputs, outputs, dataOpndVtStr);
2636
2637 }
2638 }
2639
2640 memDataOpndWidth *= 2;
2641 }
2642}
2643
2644/**
2645 * Writes bitwise NOT/AND/IOR/XOR operation definitions for vector operations.
2646 *
2647 * For 32-bit or less vector widths, 32-bit base operation is used. For
2648 * bitwise bool vector operations wider than 32 bits, corresponding bitwise
2649 * operation is searched from the machine, and used to create operation
2650 * definitions if it exists.
2651 *
2652 * @param o Output stream.
2653 * @param op Operation used to create bitwise operations.
2654 * @param skipPattern If true, operation pattern writing is skipped.
2655 */
2656void
2658 std::ostream& o, Operation& op, bool skipPattern) {
2659 o << endl;
2660
2661 if (op.numberOfOutputs() == 0) {
2662 assert(false && "Bitwise operation has 0 outputs.");
2663 }
2664
2665 int opWidth = op.output(0).width();
2666 std::vector<ValueType> vts = ValueType::vectorTypesOfWidth(opWidth);
2667
2668 for (size_t i = 0; i < vts.size(); ++i) {
2669 const ValueType& vecVt = vts[i];
2670 const TCEString vecVtStr = vecVt.valueTypeStr();
2671
2672 // Only integer value types are used in bitwise operations.
2673 if (!vecVt.isFloat_ && hasRegisterClassSupport(vecVt)) {
2674 std::vector<ValueType> inputs;
2675 std::vector<ValueType> outputs;
2676
2677 for (int i = 0; i < op.numberOfInputs(); ++i) {
2678 inputs.push_back(vecVt);
2679 }
2680 for (int i = 0; i < op.numberOfOutputs(); ++i) {
2681 outputs.push_back(vecVt);
2682 }
2683
2685 o, op, skipPattern, inputs, outputs, vecVtStr);
2686 }
2687 }
2688
2689 o << endl;
2690}
2691
2692/**
2693 * Attaches load and store operations to vector types that don't have them.
2694 *
2695 * Checks first which vector value types don't have load and store operations
2696 * for memory accessing. After collecting the value types without load/store,
2697 * the function tries to search existing load/store instructions whose
2698 * data operand width matches the vector value type that doesn't have a
2699 * load/store operation. If the function can find matching memory
2700 * instructions, it creates new memory instructions for the vector value types
2701 * by exploiting existing matching memory instructions.
2702 */
2703void
2705 std::ostream& o) {
2706
2707 const char* defaultTypeStr = mach_.is64bit() ? "i64" : "i32";
2708
2709 // Value type string of the register class.
2710 std::set<TCEString> withoutLoadOperation;
2711 std::set<TCEString> withoutStoreOperation;
2712
2713 // Collect all vector value types that are without load or store
2714 // operation support for memory accessing.
2715 std::map<TCEString, RegisterClass>::iterator it;
2716 for (it = vRegClasses_.begin(); it != vRegClasses_.end(); ++it) {
2717 const TCEString vtStr = it->first;
2718 const ValueType vt(vtStr);
2719
2720 // 32-bit and smaller vectors are covered by LDQ/LDH/LDW/STQ/STH/STW.
2721 // TODO: shoudl this have 64 also for 32-bit ADFs?
2722 if (vt.width() > maxScalarWidth_) {
2723 if (registerLoads_.find(vtStr) == registerLoads_.end()) {
2724 withoutLoadOperation.insert(vtStr);
2725 }
2726
2727 if (registerStores_.find(vtStr) == registerStores_.end()) {
2728 withoutStoreOperation.insert(vtStr);
2729 }
2730 }
2731 }
2732
2733 o << endl << "// Define memory operations for vector operands without"
2734 << endl << "// load or store operation definition by exploiting"
2735 << endl << "// existing memory operations of proper width." << endl;
2736
2737 OperationPool opPool;
2738
2739 std::set<TCEString>::const_iterator wLoadIt;
2740 for (wLoadIt = withoutLoadOperation.begin();
2741 wLoadIt != withoutLoadOperation.end(); ++wLoadIt) {
2742 const TCEString& dataOpndVtStr = *wLoadIt;
2743 const ValueType vt(dataOpndVtStr);
2744
2745 bool foundExploitable = false;
2746 std::map<TCEString, InstructionInfo>::const_iterator loadIt =
2747 registerLoads_.begin();
2748
2749 // Try to find any machine load instruction that is able to load
2750 // equal amount of bytes from memory as the ValueType is wide.
2751 while (!foundExploitable && loadIt != registerLoads_.end()) {
2752 const ValueType loadInstrVt(loadIt->first);
2753
2754 // If found a match, remove the last two characters of the
2755 // load instruction name to get the OSAL operation name.
2756 if (vt.width() == loadInstrVt.width()) {
2757 foundExploitable = true;
2758 const TCEString opName = (loadIt->second).osalOpName_;
2759 Operation& op = opPool.operation(opName.c_str());
2760
2761 std::vector<ValueType> inputs;
2762 std::vector<ValueType> outputs;
2763
2764 // Address operand always 32 or 64 bits.
2765 inputs.push_back(ValueType(defaultTypeStr));
2766 // Data operand.
2767 outputs.push_back(dataOpndVtStr);
2768
2770 o, op, false, inputs, outputs, dataOpndVtStr);
2771 }
2772
2773 ++loadIt;
2774 }
2775 }
2776
2777 std::set<TCEString>::const_iterator wStoreIt;
2778 for (wStoreIt = withoutStoreOperation.begin();
2779 wStoreIt != withoutStoreOperation.end(); ++wStoreIt) {
2780 const TCEString& dataOpndVtStr = *wStoreIt;
2781 const ValueType vt(dataOpndVtStr);
2782
2783 bool foundExploitable = false;
2784 std::map<TCEString, InstructionInfo>::const_iterator storeIt =
2785 registerStores_.begin();
2786
2787 // Try to find any machine store instruction that is able to store
2788 // equal amount of bytes to memory as the ValueType is wide.
2789 while (!foundExploitable && storeIt != registerStores_.end()) {
2790 const ValueType storeInstrVt(storeIt->first);
2791
2792 // If found a match, remove the last two characters of the
2793 // store instruction name to get the OSAL operation name.
2794 if (vt.width() == storeInstrVt.width()) {
2795 foundExploitable = true;
2796 const TCEString opName = (storeIt->second).osalOpName_;
2797 Operation& op = opPool.operation(opName.c_str());
2798
2799 std::vector<ValueType> inputs;
2800 std::vector<ValueType> outputs;
2801
2802 // Address operand always i32 or 64 bits.
2803 inputs.push_back(ValueType(defaultTypeStr));
2804 inputs.push_back(dataOpndVtStr);
2805 // There is no output operands for store.
2806
2808 o, op, false, inputs, outputs, dataOpndVtStr);
2809 }
2810
2811 ++storeIt;
2812 }
2813 }
2814
2815 o << endl;
2816}
2817
2818/**
2819 * Writes vector operation definitions that exploit bigger vector operations.
2820 *
2821 * Exploited vector operands are written in ascending order by their subword
2822 * count, meaning that e.g. ADD32X16, ADD32X32, and ADD32X4 operation
2823 * exploitations are listed so that ADD32X4 are written first, then
2824 * ADD32X16, and then ADD32X32. This way the instruction selection will
2825 * first use ADD32X4 to execute vector addition for v2i32 vector operand
2826 * types, and thus, is more optimal solution than executing the same
2827 * v2i32 addition with ADD32X16 (though ADD32X4 would be also available
2828 * in the machine).
2829 */
2830void
2834
2835/**
2836 * Generates implementation of getStore() function.
2837 */
2838void
2840 TCEString prefix = "&"; // Address of -operator.
2841 TCEString rcpf = "RegsRegClass";
2842 TCEString rapf = "TCE::RARegRegClass";
2843 TCEString storeB = littleEndian_ ? "ST8Brb;" : "STQBrb;";
2844 TCEString storeW = littleEndian_ ? "ST32" : "STW";
2845 TCEString storeH = littleEndian_ ? "ST16" : "STH";
2846 TCEString storeL = "ST64";
2847
2848 o << "#include <stdio.h>" << endl
2849 << "int GeneratedTCEPlugin::getStore(const TargetRegisterClass *rc)"
2850 << " const {" << endl;
2851
2852 o << "\tif (rc == " << prefix << rapf
2853 << ") return TCE::STWRArr;"
2854 << endl;
2855
2856 for (RegClassMap::const_iterator ri = regsInClasses_.begin();
2857 ri != regsInClasses_.end(); ri++) {
2858
2859 if ((ri->first.find("R1") == 0 ||
2860 ri->first.find(TDGen::guardRegTemplateName) == 0) &&
2861 ri->first.find("R16") != 0) {
2862 o << "\tif (rc == " << prefix << "TCE::" << ri->first
2863 << rcpf << ") return TCE::" << storeB << endl;
2864 }
2865 if (ri->first.find("R32") == 0) {
2866 o << "\tif (rc == " << prefix << "TCE::" << ri->first
2867 << rcpf << ") return TCE::" << storeW << "rr;" << endl;
2868
2869 o << "\tif (rc == " << prefix << "TCE::" << ri->first
2870 << "I" << rcpf << ") return TCE::" << storeW << "rr;" << endl;
2871
2872 o << "\tif (rc == " << prefix << "TCE::" << ri->first
2873 << "FP" << rcpf << ") return TCE::" << storeW << "fr;" << endl;
2874
2875 o << "\tif (rc == " << prefix << "TCE::" << ri->first
2876 << "HFP" << rcpf << ") return TCE::" << storeH << "hr;" << endl;
2877 }
2878 if (mach_.is64bit()) {
2879 if (ri->first.find("R64") == 0) {
2880 o << "\tif (rc == " << prefix << "TCE::" << ri->first
2881 << rcpf << ") return TCE::" << storeL << "ss;" << endl;
2882
2883 o << "\tif (rc == " << prefix << "TCE::" << ri->first
2884 << "I" << rcpf << ") return TCE::" << storeL << "ss;"
2885 << endl;
2886
2887 o << "\tif (rc == " << prefix << "TCE::" << ri->first
2888 << "DFP" << rcpf << ") return TCE::" << storeL << "ds;"
2889 << endl;
2890 }
2891 // TODO: double support here?
2892 }
2893 }
2894
2895 if (use64bitForFP_) {
2896 o << "\tif (rc == &TCE::FPRegsRegClass) return TCE::ST64fs;"
2897 << std::endl;
2898
2899 o << "\tif (rc == &TCE::HFPRegsRegClass) return TCE::ST64hs;"
2900 << std::endl;
2901 } else {
2902 o << "\tif (rc == &TCE::FPRegsRegClass) return TCE::"
2903 << storeW << "fr;" << std::endl;
2904
2905 o << "\tif (rc == &TCE::HFPRegsRegClass) return TCE::"
2906 << storeW << "hr;" << std::endl;
2907 }
2908
2909 std::map<TCEString, RegisterClass>::const_iterator it;
2910 for (it = vRegClasses_.begin(); it != vRegClasses_.end(); ++it) {
2911 const TCEString& vtStr = it->first;
2912 const RegisterClass& regClass = it->second;
2913
2914 std::map<TCEString, InstructionInfo>::const_iterator storeIt =
2915 registerStores_.find(vtStr);
2916
2917 if (storeIt != registerStores_.end()) {
2918 o << "\tif (rc == &TCE::" << regClass.name() << "RegClass) "
2919 << "return TCE::" << (storeIt->second).instrName_ << ";" << endl;
2920 } else {
2921 verbose("Warning: no store generated for RegisterClass " +
2922 regClass.name() + " to GeneratedTCEPlugin::getStore");
2923 }
2924 }
2925
2926 o << "\tstd::cerr << \"regclass id:\" <<rc->getID() << \"of size \" "
2927 << "<<rc->MC->RegsSize<< std::endl;" << std::endl;
2928 o << "\tassert(0&&\"Storing given regclass to stack not supported. "
2929 << "Bug in backend?\");"
2930 << endl
2931 << "} " << endl
2932 << endl;
2933}
2934
2935/**
2936 * Generates implementation of getLoad() function.
2937 */
2938void
2940 TCEString prefix = "&"; // Address of -operator.
2941 TCEString rcpf = "RegsRegClass";
2942 TCEString rapf = "TCE::RARegRegClass";
2943
2944 TCEString loadB = littleEndian_ ? "LD8" : "LDQ";
2945 if (!mach_.hasOperation(loadB)) {
2946 loadB = littleEndian_ ? "LDU8" : "LDQU";
2947 if (!mach_.hasOperation(loadB)) {
2948 loadB="";
2949 }
2950 }
2951
2952 TCEString loadW = littleEndian_ ? "LD32" : "LDW";
2953 TCEString loadH = littleEndian_ ? "LD16" : "LDH";
2954 TCEString loadL = "LD64";
2955 if (!mach_.hasOperation(loadH)) {
2956 loadH = littleEndian_ ? "LDU16;" : "LDHU";
2957 if (!mach_.hasOperation(loadH)) {
2958 loadH="";
2959 }
2960 }
2961
2962 o << "int GeneratedTCEPlugin::getLoad(const TargetRegisterClass *rc)"
2963 << " const {" << endl;
2964
2965 o << "\tif (rc == " << prefix << rapf << ") return TCE::"
2966 << loadW << "RAr;" << endl;
2967
2968 if (!mach_.hasOperation(loadW) && mach_.hasOperation("LDU32")) {
2969 loadW = "LDU32";
2970 }
2971
2972 for (RegClassMap::const_iterator ri = regsInClasses_.begin();
2973 ri != regsInClasses_.end(); ri++) {
2974 if ((ri->first.find("R1") == 0 ||
2975 ri->first.find(TDGen::guardRegTemplateName) == 0) &&
2976 ri->first.find("R16") != 0 && loadB != "") {
2977 o << "\tif (rc == " << prefix << "TCE::" << ri->first
2978 << rcpf <<") return TCE::" << loadB << "Br;" << endl;
2979 }
2980 if (ri->first.find("R32") == 0) {
2981 o << "\tif (rc == " << prefix << "TCE::" << ri->first
2982 << rcpf << ") return TCE::" << loadW << "rr;" << endl;
2983
2984 o << "\tif (rc == " << prefix << "TCE::" << ri->first
2985 << "I" << rcpf << ") return TCE::" << loadW << "rr;" << endl;
2986
2987 o << "\tif (rc == " << prefix << "TCE::" << ri->first
2988 << "FP" << rcpf << ") return TCE::" << loadW << "fr;" << endl;
2989 if (loadH != "") {
2990 o << "\tif (rc == " << prefix << "TCE::" << ri->first
2991 << "HFP" << rcpf << ") return TCE::" << loadH << "hr;" << endl;
2992 }
2993 }
2994 if (mach_.is64bit()) {
2995 if (ri->first.find("R64") == 0) {
2996 o << "\tif (rc == " << prefix << "TCE::" << ri->first
2997 << rcpf << ") return TCE::" << loadL << "ss;" << endl;
2998
2999 o << "\tif (rc == " << prefix << "TCE::" << ri->first
3000 << "I" << rcpf << ") return TCE::" << loadL << "ss;" << endl;
3001
3002 o << "\tif (rc == " << prefix << "TCE::" << ri->first
3003 << "DFP" << rcpf << ") return TCE::" << loadL << "ds;" << endl;
3004
3005 }
3006 }
3007 }
3008
3009 if (use64bitForFP_) {
3010 o << "\tif (rc == &TCE::FPRegsRegClass) return TCE::LD64fs;"
3011 << std::endl;
3012
3013 o << "\tif (rc == &TCE::HFPRegsRegClass) return TCE::LD64hs;"
3014 << std::endl;
3015 } else {
3016 o << "\tif (rc == &TCE::FPRegsRegClass) return TCE::"
3017 << loadW << "fr;" << std::endl;
3018
3019 o << "\tif (rc == &TCE::HFPRegsRegClass) return TCE::"
3020 << loadW << "hr;" << std::endl;
3021 }
3022
3023 std::map<TCEString, RegisterClass>::const_iterator it;
3024 for (it = vRegClasses_.begin(); it != vRegClasses_.end(); ++it) {
3025 const TCEString& vtStr = it->first;
3026 const RegisterClass& regClass = it->second;
3027
3028 std::map<TCEString, InstructionInfo>::const_iterator loadIt =
3029 registerLoads_.find(vtStr);
3030
3031 if (loadIt != registerLoads_.end()) {
3032 o << "\tif (rc == &TCE::" << regClass.name() << "RegClass) "
3033 << "return TCE::" << (loadIt->second).instrName_ << ";" << endl;
3034 } else {
3035 verbose("Warning: no load generated for RegisterClass " +
3036 regClass.name() + " to GeneratedTCEPlugin::getLoad");
3037 }
3038 }
3039
3040 o << "\tprintf(\"regclass of size %d \\n\", rc->MC->RegsSize);" << std::endl
3041 << "\tassert(0&&\"loading from stack to given regclass not supported."
3042 << " Bug in backend?\");"
3043 << endl
3044 << "} " << endl
3045 << endl;
3046}
3047
3048
3049/**
3050 * Generates a function that adds existing register classes in lowering phase.
3051 */
3052void
3054 std::ostream& o) const {
3055 o << endl << "// Adds all vector classes to backend" << endl
3056 << "void TCETargetLowering::addVectorRegisterClasses() {" << endl;
3057 std::map<TCEString, RegisterClass>::const_iterator it;
3058 for (it = vRegClasses_.begin(); it != vRegClasses_.end(); ++it) {
3059 const RegisterClass& regClass = it->second;
3060
3061 o << "\taddRegisterClass("
3062 << "MVT::" << regClass.valueType().valueTypeStr() << ", "
3063 << "&TCE::" << regClass.name() << "RegClass);"
3064 << endl;
3065 }
3066
3067 o << "}" << endl;
3068
3069 o << endl << "// Sets build and extract lowering" << endl
3070 << "void TCETargetLowering::addVectorLowerings() {" << endl;
3071
3072 for (it = vRegClasses_.begin(); it != vRegClasses_.end(); ++it) {
3073 const RegisterClass& regClass = it->second;
3074
3075 o << "\tsetOperationAction(ISD::BUILD_VECTOR,"
3076 << "MVT::" << regClass.valueType().valueTypeStr() << ", "
3077 << "Custom);" << endl;
3078
3079 o << "\tsetOperationAction(ISD::EXTRACT_SUBVECTOR,"
3080 << "MVT::" << regClass.valueType().valueTypeStr() << ", "
3081 << "Expand);" << endl;
3082
3084 if (vRegClasses_.find(vt) == vRegClasses_.end()) {
3085 o << "\tsetTruncStoreAction(MVT::"
3086 << regClass.valueType().valueTypeStr()
3087 << ", MVT::" << vt << ", Expand);" << endl;
3088 }
3089 }
3090 }
3091 o << "}" << endl;
3092}
3093
3094/**
3095 * Generates a function that returns correct reg class for a value type.
3096 */
3097void
3099 std::ostream& o) const {
3100 o << endl << "// Returns vector register class for given value type"
3101 << endl
3102 << "std::pair<unsigned, const TargetRegisterClass*> "
3103 << "TCETargetLowering::associatedVectorRegClass(const EVT& vt) "
3104 << "const {"
3105 << endl;
3106
3107 std::map<TCEString, RegisterClass>::const_iterator it;
3108 for (it = vRegClasses_.begin(); it != vRegClasses_.end(); ++it) {
3109 const TCEString& vtStr = it->first;
3110 const RegisterClass& regClass = it->second;
3111
3112 o << "\tif (vt == MVT::" << vtStr << ") "
3113 << "return std::make_pair(0U, &TCE::"
3114 << regClass.name() << "RegClass);" << endl;
3115 }
3116
3117 o << "\treturn std::make_pair(0U, (TargetRegisterClass*)0);" << endl
3118 << "}" << endl;
3119}
3120
3121/**
3122 * Generates a function that returns correct return value type for comparisons.
3123 *
3124 * In LLVM vector comparison operations result into boolean vectors,
3125 * which have the same subword count as input vectors.
3126 */
3127void
3129 o << endl
3130 << "llvm::EVT TCETargetLowering::getSetCCResultVT(const EVT& vt) "
3131 << "const {"
3132 << endl;
3133
3134 int subwCount = 2;
3135 while (subwCount <= MAX_SUBW_COUNT) {
3136 TCEString boolVecVtStr = "v" + Conversion::toString(subwCount) + "i1";
3137 ValueType boolVecVt(boolVecVtStr);
3138
3139 if (!boolVecVt.isSupportedByLLVM()) {
3140 break;
3141 }
3142
3143 o << "\tif (vt.getVectorElementCount().getKnownMinValue() == "
3144 << Conversion::toString(subwCount) << ") return llvm::MVT::"
3145 << boolVecVtStr << ";" << endl;
3146 subwCount *= 2;
3147 }
3148
3149 o << "\treturn llvm::MVT::INVALID_SIMPLE_VALUE_TYPE;" << endl
3150 << "}" << endl;
3151}
3152
3153/**
3154 * Writes return address register definition to the output stream.
3155 */
3156void
3158 o << "class Rra<string n> : TCEReg<n, []>;" << std::endl;
3159 o << "def RA : Rra<\"return-address\">, ";
3160 o << "DwarfRegNum<[" << dregNum_++ << "]>;";
3161 o << std::endl;
3162 if (mach_.is64bit()) {
3163 o << "def RAReg : RegisterClass<\"TCE\", [i64], 64, (add RA)>;" <<
3164 std::endl;
3165 } else {
3166 o << "def RAReg : RegisterClass<\"TCE\", [i32], 32, (add RA)>;" <<
3167 std::endl;
3168 }
3169}
3170
3171
3172
3173#if 0 // TODO: where does this belong???
3174
3175 o << "\treturn llvm::MVT::INVALID_SIMPLE_VALUE_TYPE;" << endl
3176 << "}" << endl;
3177}
3178#endif
3179
3180/**
3181 * Generates implementation of copyPhysVectorReg().
3182 *
3183 * Only the previously created vector register classes are added
3184 * to the implementation to make LLVM compilation flow work.
3185 */
3186void
3188 o << endl
3189 << "#include <llvm/CodeGen/MachineInstrBuilder.h>" << endl
3190 << "// Copies a vector register to another" << endl
3191
3192 << "bool TCEInstrInfo::copyPhysVectorReg(" << endl
3193 << "\tMachineBasicBlock& mbb," << endl
3194 << "\tMachineBasicBlock::iterator mbbi," << endl
3195 << "const DebugLoc& dl," << endl
3196 << "\tMCRegister destReg, MCRegister srcReg," << endl
3197 << "\tbool killSrc) const {" << endl
3198 << endl;
3199
3200 std::map<TCEString, RegisterClass>::const_iterator it;
3201 for (it = vRegClasses_.begin(); it != vRegClasses_.end(); ++it) {
3202 const RegisterClass& regClass = it->second;
3203
3204 o << "\tif (TCE::" << regClass.name()
3205 << "RegClass.contains(destReg, srcReg)) {" << endl
3206 << "\t\tBuildMI(mbb, mbbi, dl, get(TCE::"
3207 << "MOV" << regClass.name() << "), destReg)" << endl
3208 << "\t\t.addReg(srcReg, getKillRegState(killSrc));" << endl
3209 << "\t\treturn true;" << endl
3210 << "\t}" << endl;
3211 }
3212 o << "\treturn false;" << endl << "}" << endl;
3213}
3214
3215void
3216TDGen::writeVectorImmediateWriteDefs(std::ostream& instrInfoTD) {
3217 for (auto it = vRegClasses_.begin(); it != vRegClasses_.end(); ++it) {
3218 const RegisterClass& regClass = it->second;
3219 TCEString regClassName = regClass.name();
3220 ValueType valType = regClass.valueType();
3221 TCEString valTypeName = valType.valueTypeStr();
3222 if (valType.width() <= 32) {
3223 TCEString opName = "MOVI" + valTypeName;
3224 instrInfoTD << "def " << opName << " : InstTCE<(outs "
3225 << regClassName
3226 << ":$dst), (ins i32imm:$val), \"\",[]>;"
3227 << std::endl;
3228
3229 opNames_[opName] = "MOVE";
3230 }
3231 }
3232}
3233
3234void
3236 std::ostream& backendCode) const {
3237 backendCode << "int GeneratedTCEPlugin::getVectorImmediateOpcode(const "
3238 "EVT& vt) const {"
3239 << std::endl;
3240 for (auto it = vRegClasses_.begin(); it != vRegClasses_.end(); ++it) {
3241 const RegisterClass& regClass = it->second;
3242 TCEString regClassName = regClass.name();
3243 ValueType valType = regClass.valueType();
3244 TCEString valTypeName = valType.valueTypeStr();
3245 if (valType.width() <= 32) {
3246 TCEString opName = "MOVI" + valTypeName;
3247 backendCode << "\tif (vt == MVT::" << valTypeName
3248 << ") return TCE::" << opName << ";" << std::endl;
3249 }
3250 }
3251 backendCode << "\treturn -1;\n}" << endl;
3252}
3253
3254void
3256 o << endl
3257 << "// Returns correct vector GATHER opcode" << endl
3258 << "int GeneratedTCEPlugin::getGatherOpcode("
3259 << "const EVT& vt) const {" << endl;
3260
3261 for (auto it = gatherOperations_.begin(); it != gatherOperations_.end();
3262 ++it) {
3263 o << "\tif (vt == MVT::" << it->first
3264 << ") return TCE::" << it->second << ";" << endl;
3265 }
3266
3267 o << "\treturn -1;" << endl << "}" << endl;
3268}
3269
3270void
3272 o << endl
3273 << "// Returns correct load opcode" << endl
3274 << "int GeneratedTCEPlugin::getLoadOpcode("
3275 << "const EVT& vt) const {" << endl;
3276
3277 for (auto it = registerLoads_.begin(); it != registerLoads_.end(); ++it) {
3278 o << "\tif (vt == MVT::" << it->first
3279 << ") return TCE::" << it->second.instrName_ << ";" << endl;
3280 }
3281 o << "\treturn -1;" << endl << "}" << endl;
3282}
3283
3284void
3286 o << endl
3287 << "// Returns correct vector ADD opcode" << endl
3288 << "int GeneratedTCEPlugin::getAddOpcode("
3289 << "const EVT& vt) const {" << endl;
3290
3291 for (auto it = addOperations_.begin(); it != addOperations_.end(); ++it) {
3292 o << "\tif (vt == MVT::" << it->first
3293 << ") return TCE::" << it->second << ";" << endl;
3294 }
3295
3296 o << "\treturn -1;" << endl << "}" << endl;
3297}
3298
3299void
3301 o << endl
3302 << "// Returns correct vector SHL opcode" << endl
3303 << "int GeneratedTCEPlugin::getShlOpcode("
3304 << "const EVT& vt) const {" << endl;
3305
3306 for (auto it = shlOperations_.begin(); it != shlOperations_.end(); ++it) {
3307 o << "\tif (vt == MVT::" << it->first
3308 << ") return TCE::" << it->second << ";" << endl;
3309 }
3310
3311 o << "\treturn -1;" << endl << "}" << endl;
3312}
3313
3314void
3316 o << endl
3317 << "// Returns correct vector SHL opcode" << endl
3318 << "int GeneratedTCEPlugin::getIorOpcode("
3319 << "const EVT& vt) const {" << endl;
3320
3321 for (auto it = iorOperations_.begin(); it != iorOperations_.end(); ++it) {
3322 o << "\tif (vt == MVT::" << it->first
3323 << ") return TCE::" << it->second << ";" << endl;
3324 }
3325
3326 o << "\treturn -1;" << endl << "}" << endl;
3327}
3328
3329/**
3330 * Checks that the target machine has required registers to build a usable
3331 * plugin.
3332 *
3333 * @return True if required registers were found, false if not.
3334 */
3335bool
3337 if (!mach_.is64bit() && regs32bit_.size() < requiredI32Regs_) {
3338 std::string msg =
3339 (boost::format(
3340 "Architecture doesn't meet the minimal requirements.\n"
3341 "Only %d 32-bit general purpose registers found. At least %d\n"
3342 "needed.")
3343 % regs32bit_.size() % requiredI32Regs_)
3344 .str();
3345
3346 if (tempRegFiles_.size() > 0) {
3347 msg += "Your machine is not fully connected, thus one register\n"
3348 "from each register file are reserved for temp moves and\n"
3349 "not used as general purpose registers.";
3350 }
3351
3352 throw InvalidData(__FILE__, __LINE__, __func__, msg);
3353 return false;
3354 }
3355
3356 if (regs64bit_.size() < requiredI64Regs_) {
3357 std::string msg =
3358 (boost::format(
3359 "Architecture doesn't meet the minimal requirements.\n"
3360 "Only %d 64-bit general purpose registers found. At least %d\n"
3361 "needed. ")
3362 % regs64bit_.size() % requiredI64Regs_)
3363 .str();
3364
3365 if (tempRegFiles_.size() > 0) {
3366 msg += "Your machine is not fully connected, thus one register\n"
3367 "from each register file is reserved for temp moves and\n"
3368 "not used as general purpose registers.";
3369 }
3370
3371 throw InvalidData(__FILE__, __LINE__, __func__, msg);
3372 return false;
3373 }
3374
3375 return true;
3376}
3377
3378/**
3379 * Writes all machine instructions to instruction info .td file.
3380 *
3381 * @param os Output stream to the file.
3382 */
3383void
3384TDGen::writeInstrInfo(std::ostream& os) {
3385
3387
3391
3394
3395 OperationPool opPool;
3396
3397 for (int i = 0; i < fuNav.count(); i++) {
3398 const TTAMachine::FunctionUnit* fu = fuNav.item(i);
3399 for (int o = 0; o < fu->operationCount(); o++) {
3400 const std::string opName = fu->operation(o)->name();
3401 opNames.insert(StringTools::stringToUpper(opName));
3402 }
3403 }
3404
3405 if (littleEndian_) {
3406 if (mach_.is64bit()) {
3407 opNames_["ST64fa"] = "ST64";
3408 opNames_["ST64fs"] = "ST64";
3409 opNames_["ST64ha"] = "ST64";
3410 opNames_["ST64hs"] = "ST64";
3411 opNames_["ST64da"] = "ST64";
3412 opNames_["ST64ds"] = "ST64";
3413
3414 opNames_["LD64fa"] = "LD64";
3415 opNames_["LD64fs"] = "LD64";
3416 opNames_["LD64ha"] = "LD64";
3417 opNames_["LD64hs"] = "LD64";
3418 opNames_["LD64da"] = "LD64";
3419 opNames_["LD64ds"] = "LD64";
3420 }
3421
3422 if (mach_.hasOperation("LD32")) {
3423 opNames_["LD32fr"] = "LD32";
3424 opNames_["LD32fi"] = "LD32";
3425
3426 opNames_["LD32hr"] = "LD32";
3427 opNames_["LD32hi"] = "LD32";
3428
3429 } else if (mach_.hasOperation("LDU32")) {
3430 opNames_["LD32fr"] = "LDU32";
3431 opNames_["LD32fi"] = "LDU32";
3432
3433 opNames_["LD32hr"] = "LDU32";
3434 opNames_["LD32hi"] = "LDU32";
3435 }
3436 opNames_["ST32fr"] = "ST32";
3437 opNames_["ST32fi"] = "ST32";
3438
3439 opNames_["ST32hr"] = "ST32";
3440 opNames_["ST32hi"] = "ST32";
3441
3442 opNames_["ST16hr"] = "ST16";
3443 opNames_["ST16hi"] = "ST16";
3444 } else {
3445 opNames_["LDWfr"] = "LDW";
3446 opNames_["LDWfi"] = "LDW";
3447 opNames_["LDWhr"] = "LDW";
3448 opNames_["LDWhi"] = "LDW";
3449
3450 opNames_["STWfr"] = "STW";
3451 opNames_["STWfi"] = "STW";
3452
3453 opNames_["STWhr"] = "STW";
3454 opNames_["STWhi"] = "STW";
3455 opNames_["STHhr"] = "STH";
3456 opNames_["STHhi"] = "STH";
3457 }
3458
3459 // Some global/address immediate if conversion fails
3460 // so commented out.
3461 // TODO: ^ up-to-date comment? ^
3463
3464 if (mach_.is64bit()) {
3465 truePredOps_["MOV64ss"] = "PRED_TRUE_MOV64ss";
3466 falsePredOps_["MOV64ss"] = "PRED_FALSE_MOV64ss";
3467 }
3468
3469 truePredOps_["MOVI32rr"] = "PRED_TRUE_MOVI32rr";
3470 falsePredOps_["MOVI32rr"] = "PRED_FALSE_MOVI32rr";
3471 truePredOps_["MOVI1rr"] = "PRED_TRUE_MOVI1rr";
3472 falsePredOps_["MOVI1rr"] = "PRED_FALSE_MOVI1rr";
3473 }
3474
3475 OperationDAGSelector::OperationSet::const_iterator iter = opNames.begin();
3476 for (; iter != opNames.end(); iter++) {
3477 OperationDAGSelector::OperationSet::iterator r =
3478 requiredOps.find(*iter);
3479 if (r != requiredOps.end()) {
3480 requiredOps.erase(r);
3481 }
3482 Operation& op = opPool.operation((*iter).c_str());
3483 bool skipPattern = false;
3484
3485 if (&op == &NullOperation::instance()) {
3486 continue;
3487 }
3488
3489 // TODO: Allow multioutput (remove last or)
3490 if (!operationCanBeMatched(op)) {
3491 // TODO: write opeation def without graphs
3492 if (&op != &NullOperation::instance()) {
3493 skipPattern = true;
3494 if (Application::verboseLevel() > 0) {
3496 << "Skipped writing operation pattern for "
3497 << op.name() << endl;
3498 }
3499 } else {
3500 // NULL op - ignore
3501 continue;
3502 }
3503 }
3504
3505 // TODO: remove this. For now MIMO operation patterns are not
3506 // supported by tablegen.
3507 if (op.numberOfOutputs() > 1) {
3508 skipPattern = true;
3509 continue;
3510 }
3511
3512 if (op.isVectorOperation()) {
3514 writeVectorMemoryOperationDefs(os, op, skipPattern);
3515 } else if (isVectorBitwiseOperation(op)) {
3516 writeVectorBitwiseOperationDefs(os, op, skipPattern);
3517 } else {
3518 writeVectorOperationDefs(os, op, skipPattern);
3519 }
3520 } else {
3521 writeOperationDefs(os, op, skipPattern);
3522 }
3523 }
3524
3532
3533 // Call operations.
3535
3536 // Hardware loop instructions
3537 writeHWLoopDef(os);
3538
3539 // Emulated operations.
3540 for (iter = requiredOps.begin(); iter != requiredOps.end(); iter++) {
3541 const Operation& op = opPool.operation((*iter).c_str());
3542
3543 if (&op == &NullOperation::instance()) {
3544 std::string msg = "Required OP '" + *iter + "' not found.";
3545 throw InvalidData(__FILE__, __LINE__, __func__, msg);
3546 }
3547
3548 const OperationDAGSelector::OperationDAGList emulationDAGs =
3550
3551 if (emulationDAGs.empty()) {
3554 Application::logStream() << "Warning: Operation '" << *iter
3555 << "' not supported." << endl;
3556 }
3557 } else {
3558 /// @note This todo marking is from TDGenSIMD
3559 // TODO: write all dags of operation (first as normal, the rest
3560 // as pattern)
3561 writeEmulationPattern(os, op, emulationDAGs.smallestNodeCount());
3562 }
3563 }
3564
3567 if (mach_.is64bit()) {
3569 }
3570
3572
3578}
3579
3580void TDGen::writeCallDefRegs(std::ostream& o) {
3581 for (unsigned i = 0; i < resRegNames_.size(); i++) {
3582 if (i > 0) o << ", ";
3583 o << resRegNames_[i];
3584 }
3585 for (unsigned i = 0; i < gprRegNames_.size(); i++) {
3586 o << ", " << gprRegNames_[i];
3587 }
3588
3589 // call dest may call others which may mess up these
3590 for (unsigned i = 0; i < argRegNames_.size(); i++) {
3591 o << ", " << argRegNames_[i];
3592 }
3593
3594 std::map<int, std::vector<RegisterInfo>>::const_iterator it;
3595 for (it = registers_.begin(); it != registers_.end(); ++it) {
3596 int regsWidth = it->first;
3597
3598 const std::vector<RegisterInfo>& regs = it->second;
3599 TCEString baseClass = baseClasses_.find(regsWidth)->second;
3600
3601 for (size_t i = 0; i < regs.size(); ++i) {
3602 // Don't declare <=32b registers again, it has been done in TDGen.
3603 if (regsWidth > maxScalarWidth_) {
3604 RegisterInfo reg = regs[i];
3605 o << ", " << reg.regName_;
3606 }
3607 }
3608 }
3609}
3610
3611
3612/**
3613 * Writes control flow instructions definitions and patterns
3614 */
3615void
3617
3619
3620 writeCallDef(os);
3621}
3622
3623/**
3624 * Writes hwloop instructions and patterns.
3625 */
3626void
3627TDGen::writeHWLoopDef(std::ostream& os) {
3628 os << std::endl << "// Hardware loop instructions" << std::endl;
3629 if (mach_.controlUnit()->hasOperation("hwloop")) {
3630 os << "let isTerminator=1 in {" << std::endl
3631 << " def HWLOOPii : InstTCE<(outs), (ins i32imm0:$rIter, "
3632 "i32imm0:$rInstr), \"\", []>;"
3633 << std::endl
3634 << " def HWLOOPri : InstTCE<(outs), (ins i32imm0:$rIter, "
3635 "i32imm0:$rInstr), \"\", []>;"
3636 << std::endl
3637 << "}" << std::endl
3638 << "def : Pat<(int_set_loop_iterations i32imm0:$rIter), "
3639 "(HWLOOPii i32imm0:$rIter, 0)>;"
3640 << std::endl
3641 << "def : Pat<(int_set_loop_iterations R32IRegs:$rIter), "
3642 "(HWLOOPri R32IRegs:$rIter, 0)>;"
3643 << std::endl;
3644 opNames_["HWLOOPii"] = "hwloop";
3645 opNames_["HWLOOPri"] = "hwloop";
3646 }
3647
3648 // Write loop jump pseudo
3649 os << "let isTerminator = 1 in {" << std::endl
3650 << " def LJUMP : InstTCE<(outs), (ins brtarget:$dst), \"\", []>;"
3651 << std::endl
3652 << "}" << std::endl
3653 << std::endl;
3654 opNames_["LJUMP"] = "PSEUDO";
3655}
3656
3657/**
3658 * Writes instructions definitions and patterns for conditional branches.
3659 */
3660void
3662
3663 auto cuOpset = MachineInfo::getOpset(*mach_.controlUnit());
3664
3666
3667 os << std::endl << "let isTerminator = 1, isBranch = 1 in {" << std::endl;
3668
3669 if (cuOpset.count("JUMP") && opNames_.count("TCEBRCOND") == 0) {
3670 writeInstrDef(os, "TCEBRCOND", "",
3671 "GuardRegs:$gr, brtarget:$dst",
3672 "? $gr $dst -> jump.1;",
3673 "(brcond GuardRegs:$gr, bb:$dst)");
3674 os << std::endl;
3675 opNames_["TCEBRCOND"] = "?jump";
3676 }
3677
3678 if (cuOpset.count("JUMP") && opNames_.count("TCEBRICOND") == 0) {
3679 writeInstrDef(os, "TCEBRICOND", "",
3680 "GuardRegs:$gr, brtarget:$dst",
3681 "! $gr $dst -> jump.1;",
3682 "(brcond (not GuardRegs:$gr), bb:$dst)");
3683 opNames_["TCEBRICOND"] = "!jump";
3684 }
3685 os << "}" << std::endl;
3686
3687 // generate brcc pseudo jumps. these are split in llvmtcebuilder into
3688 // separate comparison and jump.
3690
3691 if (!writePortGuardedJumpDefPair(os, "EQ", "NE")) {
3692 abortWithError("Required eq/ne op not found. please add to adf.");
3693 }
3694 if (!writePortGuardedJumpDefPair(os, "GT", "LE")) {
3695 abortWithError("Required gt/le op not found. please add to adf.");
3696 }
3697 if (!writePortGuardedJumpDefPair(os, "GTU", "LEU")) {
3698 abortWithError("Required gtu/leu op not found. please add to adf.");
3699 }
3700
3701 // floating point ops are optional.
3702 writePortGuardedJumpDefPair(os, "EQF", "NEF", true);
3703 writePortGuardedJumpDefPair(os, "LEF", "GTF", true);
3704 writePortGuardedJumpDefPair(os, "LTF", "GEF", true);
3705
3706 if (MachineInfo::supportsPortGuardedJump(mach_, false, "AND")) {
3707 writeInstrDef(os, "AND_JUMP", "",
3708 "R32IRegs:$cmp1, R32IRegs:$cmp2, brtarget:$dst", "",
3709 "(brcond (and R32IRegs:$cmp1, R32IRegs:$cmp2), bb:$dst)");
3710 } else {
3711 std::cerr << "Missing AND operation as true-guard source to jump." << std::endl;
3712 assert(false);
3713 }
3714
3715 if (MachineInfo::supportsPortGuardedJump(mach_, false, "IOR")) {
3716 writeInstrDef(os, "IOR_JUMP", "",
3717 "R32IRegs:$cmp1, R32IRegs:$cmp2, brtarget:$dst", "",
3718 "(brcond (or R32IRegs:$cmp1, R32IRegs:$cmp2), bb:$dst)");
3719 } else {
3720 std::cerr << "Missing IOR operation as true-guard source to jump." << std::endl;
3721 assert(false);
3722 }
3723
3724 os << std::endl << "let isTerminator = 1, isBranch = 1 in {" << std::endl;
3725
3726 // dummy br(i)cond ops
3727 writeInstrDef(os, "TCEBRCOND", "",
3728 "GuardRegs:$gr, brtarget:$dst",
3729 "? $gr $dst -> jump.1;",
3730 "");
3731 os << std::endl;
3732
3733 writeInstrDef(os, "TCEBRICOND", "",
3734 "GuardRegs:$gr, brtarget:$dst",
3735 "? $gr $dst -> jump.1;",
3736 "");
3737 os << std::endl;
3738
3739
3740 os << "}" << std::endl;
3741
3742 os << "def: Pat<(brcc SETLT, R32IRegs:$cmp1, R32IRegs:$cmp2, bb:$dst),"
3743 << " (GT_JUMP R32IRegs:$cmp2, R32IRegs:$cmp1, brtarget:$dst)>;" << std::endl;
3744
3745
3746 os << "def: Pat<(brcc SETGE, R32IRegs:$cmp1, R32IRegs:$cmp2, bb:$dst),"
3747 << " (LE_JUMP R32IRegs:$cmp2, R32IRegs:$cmp1, brtarget:$dst)>;" << std::endl;
3748
3749 os << "def: Pat<(brcc SETULT, R32IRegs:$cmp1, R32IRegs:$cmp2, bb:$dst),"
3750 << " (GTU_JUMP R32IRegs:$cmp2, R32IRegs:$cmp1, brtarget:$dst)>;" << std::endl;
3751
3752
3753 os << "def: Pat<(brcc SETUGE, R32IRegs:$cmp1, R32IRegs:$cmp2, bb:$dst),"
3754 << " (LEU_JUMP R32IRegs:$cmp2, R32IRegs:$cmp1, brtarget:$dst)>;" << std::endl;
3755
3756
3757 opNames_["AND_JUMP"] = "and+?jump";
3758 opNames_["IOR_JUMP"] = "ior+?jump";
3759
3760 // conditional jumps without guard.
3761 } else {
3762
3763 os << std::endl << "let isTerminator = 1, isBranch = 1 in {" << std::endl;
3764
3765 if (cuOpset.count("BNZ1")) {
3766 // TODO: Check if has R1 regs or not!
3767
3768 writeInstrDef(os, "TCEBRCOND", "", "R32IRegs:$gr, brtarget:$dst",
3769 "", "(brcond R32IRegs:$gr, bb:$dst)");
3770 os << std::endl;
3771 opNames_["TCEBRCOND"] = "BNZ1";
3772 } else {
3773 if (cuOpset.count("BNZ")) {
3774 writeInstrDef(os, "TCEBRCOND", "", "R32IRegs:$gr, brtarget:$dst",
3775 "", "(brcond R32IRegs:$gr, bb:$dst)");
3776 os << std::endl;
3777 opNames_["TCEBRCOND"] = "BNZ";
3778 } else {
3779 std::cerr << "Does not have guarded jumps or neither bnz or bnz1" << std::endl;
3780 }
3781 }
3782
3783 if (cuOpset.count("BZ1")) {
3784 // TODO: Check if has R1 regs or not!
3785
3786 writeInstrDef(os, "TCEBRICOND", "", "R32IRegs:$gr, brtarget:$dst",
3787 "", "(brcond (not R32IRegs:$gr), bb:$dst)");
3788 os << std::endl;
3789 opNames_["TCEBRICOND"] = "BZ1";
3790 } else {
3791 if (cuOpset.count("BZ")) {
3792 writeInstrDef(os, "TCEBRICOND", "", "R32IRegs:$gr, brtarget:$dst",
3793 "", "(brcond (not R32IRegs:$gr), bb:$dst)");
3794 os << std::endl;
3795 opNames_["TCEBRICOND"] = "BZ";
3796 } else {
3797 std::cerr << "Does not have guarded jumps or neither bz or bz1" << std::endl;
3798 }
3799 }
3800
3801 if (cuOpset.count("BEQ")) {
3802 writeInstrDef(os, "TCEBREQrr", "", "R32IRegs:$c1, R32IRegs:$c2, brtarget:$dst",
3803 "", "(brcond (i32 (seteq R32IRegs:$c1, R32IRegs:$c2)), bb:$dst)");
3804 opNames_["TCEBREQrr"] = "BEQ";
3805 writeInstrDef(os, "TCEBREQri", "", "R32IRegs:$c1, i32imm:$c2, brtarget:$dst",
3806 "", "(brcond (i32 (seteq R32IRegs:$c1, i32MoveImm:$c2)), bb:$dst)");
3807 opNames_["TCEBREQri"] = "BEQ";
3808 }
3809
3810 if (cuOpset.count("BNE")) {
3811 writeInstrDef(os, "TCEBRNErr", "", "R32IRegs:$c1, R32IRegs:$c2, brtarget:$dst",
3812 "", "(brcond (i32 (setne R32IRegs:$c1, R32IRegs:$c2)), bb:$dst)");
3813 opNames_["TCEBRNErr"] = "BNE";
3814 writeInstrDef(os, "TCEBRNEri", "", "R32IRegs:$c1, i32imm:$c2, brtarget:$dst",
3815 "", "(brcond (i32 (setne R32IRegs:$c1, i32MoveImm:$c2)), bb:$dst)");
3816 opNames_["TCEBRNEri"] = "BNE";
3817 }
3818
3819 if (cuOpset.count("BGT")) {
3820 writeInstrDef(os, "TCEBRGTrr", "", "R32IRegs:$c1, R32IRegs:$c2, brtarget:$dst",
3821 "", "(brcond (i32 (setgt R32IRegs:$c1, R32IRegs:$c2)), bb:$dst)");
3822 opNames_["TCEBRGTrr"] = "BGT";
3823 writeInstrDef(os, "TCEBRGTri", "", "R32IRegs:$c1, i32imm:$c2, brtarget:$dst",
3824 "", "(brcond (i32 (setgt R32IRegs:$c1, i32MoveImm:$c2)), bb:$dst)");
3825 opNames_["TCEBRGTri"] = "BGT";
3826 }
3827
3828 if (cuOpset.count("BGTU")) {
3829 writeInstrDef(os, "TCEBRGTUrr", "", "R32IRegs:$c1, R32IRegs:$c2, brtarget:$dst",
3830 "", "(brcond (i32 (setugt R32IRegs:$c1, R32IRegs:$c2)), bb:$dst)");
3831 opNames_["TCEBRGTUrr"] = "BGTU";
3832 writeInstrDef(os, "TCEBRGTUri", "", "R32IRegs:$c1, i32imm:$c2, brtarget:$dst",
3833 "", "(brcond (i32 (setugt R32IRegs:$c1, i32MoveImm:$c2)), bb:$dst)");
3834 opNames_["TCEBRGTUri"] = "BGTU";
3835 }
3836
3837 if (cuOpset.count("BLT")) {
3838 writeInstrDef(os, "TCEBRLTrr", "", "R32IRegs:$c1, R32IRegs:$c2, brtarget:$dst",
3839 "", "(brcond (i32 (setlt R32IRegs:$c1, R32IRegs:$c2)), bb:$dst)");
3840 opNames_["TCEBRLTrr"] = "BLT";
3841 writeInstrDef(os, "TCEBRLTri", "", "R32IRegs:$c1, i32imm:$c2, brtarget:$dst",
3842 "", "(brcond (i32 (setlt R32IRegs:$c1, i32MoveImm:$c2)), bb:$dst)");
3843 opNames_["TCEBRLTri"] = "BLT";
3844 }
3845
3846 if (cuOpset.count("BLTU")) {
3847 writeInstrDef(os, "TCEBRLTUrr", "", "R32IRegs:$c1, R32IRegs:$c2, brtarget:$dst",
3848 "", "(brcond (i32 (setult R32IRegs:$c1, R32IRegs:$c2)), bb:$dst)");
3849 opNames_["TCEBRLTUrr"] = "BLTU";
3850 writeInstrDef(os, "TCEBRLTUri", "", "R32IRegs:$c1, i32imm:$c2, brtarget:$dst",
3851 "", "(brcond (i32 (setult R32IRegs:$c1, i32MoveImm:$c2)), bb:$dst)");
3852 opNames_["TCEBRLTUri"] = "BLTU";
3853 }
3854
3855 if (cuOpset.count("BLE")) {
3856 writeInstrDef(os, "TCEBRLErr", "", "R32IRegs:$c1, R32IRegs:$c2, brtarget:$dst",
3857 "", "(brcond (i32 (setle R32IRegs:$c1, R32IRegs:$c2)), bb:$dst)");
3858 opNames_["TCEBRLErr"] = "BLE";
3859 writeInstrDef(os, "TCEBRLEri", "", "R32IRegs:$c1, i32imm:$c2, brtarget:$dst",
3860 "", "(brcond (i32 (setle R32IRegs:$c1, i32MoveImm:$c2)), bb:$dst)");
3861 opNames_["TCEBRLEri"] = "BLE";
3862 }
3863
3864 if (cuOpset.count("BLEU")) {
3865 writeInstrDef(os, "TCEBRLEUrr", "", "R32IRegs:$c1, R32IRegs:$c2, brtarget:$dst",
3866 "", "(brcond (i32 (setule R32IRegs:$c1, R32IRegs:$c2)), bb:$dst)");
3867 opNames_["TCEBRLEUrr"] = "BLEU";
3868 writeInstrDef(os, "TCEBRLEUri", "", "R32IRegs:$c1, i32imm:$c2, brtarget:$dst",
3869 "", "(brcond (i32 (setule R32IRegs:$c1, i32MoveImm:$c2)), bb:$dst)");
3870 opNames_["TCEBRLEUri"] = "BLEU";
3871 }
3872
3873 if (cuOpset.count("BGE")) {
3874 writeInstrDef(os, "TCEBRGErr", "", "R32IRegs:$c1, R32IRegs:$c2, brtarget:$dst",
3875 "", "(brcond (i32 (setge R32IRegs:$c1, R32IRegs:$c2)), bb:$dst)");
3876 opNames_["TCEBRGErr"] = "BGE";
3877 writeInstrDef(os, "TCEBRGEri", "", "R32IRegs:$c1, i32imm:$c2, brtarget:$dst",
3878 "", "(brcond (i32 (setge R32IRegs:$c1, i32MoveImm:$c2)), bb:$dst)");
3879 opNames_["TCEBRGEri"] = "BGE";
3880 }
3881
3882 if (cuOpset.count("BGEU")) {
3883 writeInstrDef(os, "TCEBRGEUrr", "", "R32IRegs:$c1, R32IRegs:$c2, brtarget:$dst",
3884 "", "(brcond (i32 (setuge R32IRegs:$c1, R32IRegs:$c2)), bb:$dst)");
3885 opNames_["TCEBRGEUrr"] = "BGEU";
3886 writeInstrDef(os, "TCEBRGEUri", "", "R32IRegs:$c1, i32imm:$c2, brtarget:$dst",
3887 "", "(brcond (i32 (setuge R32IRegs:$c1, i32MoveImm:$c2)), bb:$dst)");
3888 opNames_["TCEBRGEUri"] = "BGEU";
3889 }
3890
3891 os << "}" << std::endl;
3892 }
3893}
3894
3895
3896
3898 std::ostream& os, const TCEString& tceop1, const TCEString& tceop2, bool fp) {
3899
3900 TCEString llvmop1 = TDGen::llvmOperationName(tceop1).upper();
3901 TCEString llvmop2 = TDGen::llvmOperationName(tceop2).upper();
3902
3903 TCEString regclass = fp ? "R32FPRegs" : "R32IRegs";
3904 if (MachineInfo::supportsPortGuardedJump(mach_, false, tceop1) ||
3906
3907 os << std::endl << "let isTerminator = 1, isBranch = 1 in {" << std::endl;
3908
3909 writeInstrDef(os, tceop1+"_JUMP", "",
3910 regclass + ":$cmp1, "+ regclass + ":$cmp2, brtarget:$dst", "",
3911 "(brcc "+ llvmop1 +", "+ regclass + ":$cmp1, " + regclass + ":$cmp2, bb:$dst)");
3912
3913 os << "}" << std::endl;
3914 if (MachineInfo::supportsPortGuardedJump(mach_, false, tceop1)) {
3915 opNames_[tceop1 + "_JUMP"] = tceop1 + "+?jump";
3916 } else {
3917 opNames_[tceop1 + "_JUMP"] = tceop2 + "+!jump";
3918 }
3919 } else {
3920 std::cerr << "Missing "<< tceop1 << " operation as true-guard source"
3921 << " or " << tceop2 << " operation as invarted guard source to jump." << std::endl;
3922 return false;
3923 }
3924
3925 if (MachineInfo::supportsPortGuardedJump(mach_, true, tceop1) ||
3927
3928 os << std::endl << "let isTerminator = 1, isBranch = 1 in {" << std::endl;
3929
3930
3931 writeInstrDef(os, tceop2+"_JUMP", "",
3932 regclass + ":$cmp1, "+ regclass + ":$cmp2, brtarget:$dst", "",
3933 "(brcc "+ llvmop2 +", "+ regclass + ":$cmp1, " + regclass + ":$cmp2, bb:$dst)");
3934
3935 os << "}" << std::endl;
3936
3937 if (MachineInfo::supportsPortGuardedJump(mach_, false, tceop2)) {
3938 opNames_[tceop2 + "_JUMP"] = tceop2 + "+?jump";
3939 } else {
3940 opNames_[tceop2 + "_JUMP"] = tceop1 + "+!jump";
3941 }
3942 } else {
3943 std::cerr << "Missing " << tceop2 << " operation as true-guard source"
3944 << " or " << tceop1 << " operation as inverted guard source to jump."
3945 << std::endl;
3946 return false;
3947 }
3948 return true;
3949}
3950
3951/**
3952 * Writes .td pattern for the call instruction(s) to the output stream.
3953 */
3954void
3955TDGen::writeCallDef(std::ostream& o) {
3956 o << "let ";
3957
3958 if (!argRegNames_.empty()) {
3959 o << "Uses = [";
3960 for (unsigned i = 0; i < argRegNames_.size(); i++) {
3961 if (i > 0) o << ", ";
3962 o << argRegNames_[i];
3963 }
3964 o << "],";
3965 }
3966
3967 o << "hasDelaySlot = 1, isCall = 1,";
3968 o << "Defs = [";
3969
3971
3972 o << "] in {" << std::endl;
3973 o << "def CALL : InstTCE<(outs), (ins calltarget:$dst),";
3974 o << "\"$dst -> call.1;\", []>;" << std::endl;
3975
3976 o << "def CALL_MEMrr : InstTCE<(outs), (ins MEMrr:$ptr),";
3977 o << "\"$ptr -> call.1;\", [(call ADDRrr:$ptr)]>;" << std::endl;
3978
3979 o << "def CALL_MEMri : InstTCE<(outs), (ins MEMri:$ptr),";
3980 o << "\"$ptr -> call.1;\", [(call ADDRri:$ptr)]>;" << std::endl;
3981 o << "}" << std::endl;
3982
3983 o << "def : Pat<(call tglobaladdr:$dst), (CALL tglobaladdr:$dst)>;"
3984 << std::endl;
3985
3986 o << "def : Pat<(call texternalsym:$dst), (CALL texternalsym:$dst)>;"
3987 << std::endl;
3988
3989}
3990
3991/**
3992 * Generates required function definitions for the backend plugin.
3993 *
3994 * @param o Output stream to write the c++ code to.
3995 */
3996void
3997TDGen::writeBackendCode(std::ostream& o) {
3998 // Register & operation info table initialization
3999
4000 o << "void" << std::endl
4001 << "GeneratedTCEPlugin::initialize() {" << std::endl;
4002
4003 // operation names
4004 std::map<std::string, std::string>::const_iterator iter =
4005 opNames_.begin();
4006
4007 for (; iter != opNames_.end(); iter++) {
4008 o << " opNames_[TCE::" << (*iter).first
4009 << "] = \"" << (*iter).second
4010 << "\";" << std::endl;
4011 }
4012
4013 for (iter = truePredOps_.begin(); iter != truePredOps_.end(); iter++) {
4014 o << " truePredOps_[TCE::" << (*iter).first
4015 << "] = TCE::" << (*iter).second
4016 << ";" << std::endl;
4017 }
4018
4019 for (iter = falsePredOps_.begin(); iter != falsePredOps_.end(); iter++) {
4020 o << " falsePredOps_[TCE::" << (*iter).first
4021 << "] = TCE::" << (*iter).second
4022 << ";" << std::endl;
4023 }
4024
4025 // Register names & indices
4026 std::map<std::string, RegInfo>::const_iterator rIter = regs_.begin();
4027 rIter = regs_.begin();
4028 for (; rIter != regs_.end(); rIter++) {
4029 const RegInfo& regInfo = rIter->second;
4030 o << " regNames_[TCE::" << (*rIter).first
4031 << "] = \"" << regInfo.rf
4032 << "\";" << std::endl;
4033
4034 o << " regIndices_[TCE::" << (*rIter).first
4035 << "] = " << regInfo.idx
4036 << ";" << std::endl;
4037
4038 TCEString ttaRegName = regInfo.rf + "." + std::to_string(regInfo.idx);
4039 o << " ttallvmRegMap_[\"" << ttaRegName << "\"] = "
4040 << "TCE::" << (*rIter).first << ";" << std::endl;
4041 }
4042
4043 // Supported stack access opcodes
4044 o << std::endl;
4045 for (std::string opName : supportedStackAccessOperations(mach_)) {
4046 o << " validStackAccessOperations_.insert(\"" << opName << "\");"
4047 << std::endl;
4048 }
4049
4050 // data address space
4053 std::string asName = "";
4054 for (int i = 0; i < nav.count(); i++) {
4055 if (nav.item(i) != mach_.controlUnit() &&
4056 nav.item(i)->addressSpace() != NULL) {
4057 asName = nav.item(i)->addressSpace()->name();
4058 }
4059 }
4060
4061 if (asName == "") {
4062 std::string msg = "Couldn't determine data address space.";
4063 throw InvalidData(__FILE__, __LINE__, __func__, msg);
4064 }
4065 o << " dataASName_ = \"" << asName << "\";" << std::endl;
4066
4067 o << "}" << std::endl;
4068
4069
4070 bool hasSDIV = false;
4071 bool hasUDIV = false;
4072 bool hasSREM = false;
4073 bool hasUREM = false;
4074 bool hasMUL = false;
4075 bool hasROTL = false;
4076 bool hasROTR = false;
4077 bool hasSXHW = false;
4078 bool hasSXQW = false;
4079 bool hasSQRTF = false;
4080 bool hasSHR = false;
4081 bool hasSHRU = false;
4082 bool hasSHL = false;
4083 bool has8bitLoads = false;
4084 bool has16bitLoads = false;
4085// bool has32bitLoads = false; // used only for 64-bit system
4086
4089
4090 for (int i = 0; i < fuNav.count(); i++) {
4091 const TTAMachine::FunctionUnit* fu = fuNav.item(i);
4092 for (int o = 0; o < fu->operationCount(); o++) {
4093 const std::string opName =
4095
4096 if (mach_.is64bit()) {
4097 if (opName == "div64") hasSDIV = true;
4098 if (opName == "divu64") hasUDIV = true;
4099 if (opName == "mod64") hasSREM = true;
4100 if (opName == "modu64") hasUREM = true;
4101 if (opName == "mul64") hasMUL = true;
4102 if (opName == "rotl64") hasROTL = true;
4103 if (opName == "rotr64") hasROTR = true;
4104 if (opName == "sxh64") hasSXHW = true;
4105 if (opName == "sxq64") hasSXQW = true;
4106 if (opName == "shr64") hasSHR = true;
4107 if (opName == "shru64") hasSHRU = true;
4108 if (opName == "shl64") hasSHL = true;
4109 } else {
4110 if (opName == "div") hasSDIV = true;
4111 if (opName == "divu") hasUDIV = true;
4112 if (opName == "mod") hasSREM = true;
4113 if (opName == "modu") hasUREM = true;
4114 if (opName == "mul") hasMUL = true;
4115 if (opName == "rotl") hasROTL = true;
4116 if (opName == "rotr") hasROTR = true;
4117 if (opName == "sxhw") hasSXHW = true;
4118 if (opName == "sxqw") hasSXQW = true;
4119 if (opName == "shr") hasSHR = true;
4120 if (opName == "shru") hasSHRU = true;
4121 if (opName == "shl") hasSHL = true;
4122 }
4123 if (opName == "sqrtf") hasSQRTF = true;
4124
4125 if (littleEndian_) {
4126 if (opName == "ld16" || opName == "ldu16") {
4127 has16bitLoads = true;
4128 } else if(opName == "ld8" || opName == "ldu8") {
4129 has8bitLoads = true;
4130// } else if (opName == "ld32" || opName == "ldu32") {
4131// has32bitLoads = true;
4132 }
4133 } else {
4134 if (opName == "ldh" || opName == "ldhu") {
4135 has16bitLoads = true;
4136 } else if (opName == "ldq" || opName == "ldqu") {
4137 has8bitLoads = true;
4138// } else if (opName == "ldw") {
4139// has32bitLoads = true;
4140 }
4141 }
4142 }
4143 }
4144
4145 o << "bool GeneratedTCEPlugin::hasSDIV() const { return "
4146 << hasSDIV << "; }" << std::endl
4147 << "bool GeneratedTCEPlugin::hasUDIV() const { return "
4148 << hasUDIV << "; }" << std::endl
4149 << "bool GeneratedTCEPlugin::hasSREM() const { return "
4150 << hasSREM << "; }" << std::endl
4151 << "bool GeneratedTCEPlugin::hasUREM() const { return "
4152 << hasUREM << "; }" << std::endl
4153 << "bool GeneratedTCEPlugin::hasMUL() const { return "
4154 << hasMUL << "; }" << std::endl
4155 << "bool GeneratedTCEPlugin::hasROTL() const { return "
4156 << hasROTL << "; }" << std::endl
4157 << "bool GeneratedTCEPlugin::hasROTR() const { return "
4158 << hasROTR << "; }" << std::endl
4159 << "bool GeneratedTCEPlugin::hasSXHW() const { return "
4160 << hasSXHW << "; }" << std::endl
4161 << "bool GeneratedTCEPlugin::hasSXQW() const { return "
4162 << hasSXQW << "; }" << std::endl
4163 << "bool GeneratedTCEPlugin::hasSQRTF() const { return "
4164 << hasSQRTF << "; }" << std::endl
4165 << "bool GeneratedTCEPlugin::hasSHR() const { return "
4166 << hasSHR << "; }" << std::endl
4167 << "bool GeneratedTCEPlugin::hasSHL() const { return "
4168 << hasSHL << "; }" << std::endl
4169 << "bool GeneratedTCEPlugin::hasSHRU() const { return "
4170 << hasSHRU << ";}" << std::endl
4171 << "bool GeneratedTCEPlugin::has8bitLoads() const { return "
4172 << has8bitLoads << ";}" << std::endl
4173 << "bool GeneratedTCEPlugin::has16bitLoads() const { return "
4174 << has16bitLoads << ";}" << std::endl;
4175// << "bool GeneratedTCEPlugin::has32bitLoads() const { return "
4176// << has32bitLoads << ";}" << std::endl
4177
4178 o << "int GeneratedTCEPlugin::maxVectorSize() const { return "
4179 << maxVectorSize_ << "; }" << std::endl;
4180
4181 // create dummy version here
4183
4192
4201}
4202
4204 std::ostream& os) const {
4205 os << "void TCERegisterInfo::setReservedVectorRegs("
4206 << "llvm::BitVector& reserved) const {" << std::endl;
4207
4208 std::set<TCEString> processedRegs;
4209 for (auto rcIt : vRegClasses_) {
4210 const RegisterClass& regClass = rcIt.second;
4211
4212 int width = regClass.valueType().width();
4213 if (regClass.numberOfRegisters() > 0) {
4214 const TCEString& name = regClass.registerInfo(0).regName_;
4215 if (processedRegs.find(name) == processedRegs.end() &&
4216 width > maxScalarWidth_) {
4217 processedRegs.insert(name);
4218 os << "reserved.set(TCE::" << name << ");" << std::endl;
4219 }
4220 }
4221 }
4222 os << "}" << std::endl;
4223}
4224
4225/**
4226 * Writes a top level TCE.td file which includes generated .td definitions.
4227 *
4228 * @param o Output stream to the file.
4229 */
4230void
4231TDGen::writeTopLevelTD(std::ostream& o) {
4232 o << "include \"Target.td\"" << std::endl;
4233 o << "include \"TCEItinerary.td\"" << std::endl;
4234 o << "include \"GenRegisterInfo.td\"" << std::endl;
4235 o << "include \"GenTCEInstrFormats.td\"" << std::endl;
4236 o << "include \"TCEInstrInfo.td\"" << std::endl;
4237 o << "include \"GenCallingConv.td\"" << std::endl;
4238 o << "def TCEInstrInfo : InstrInfo { }" << std::endl;
4239 o << "class Proc<string Name, SchedMachineModel Model,";
4240 o << " list<SubtargetFeature> Features>";
4241 o << " : ProcessorModel<Name, Model, Features>;";
4242 o << std::endl;
4243 o << "def : Proc<\"generic\", TCEModelV0,[]>;";
4244 o << std::endl;
4245 o << "def TCE : Target { let InstructionSet = TCEInstrInfo; }"
4246 << std::endl;
4247}
4248
4249/**
4250 * Writes details about instruction formatting
4251 *
4252 * @param o Output stream to the file.
4253 */
4254void
4256 o << "//" << endl;
4257 o << "// TCE Instruction formats." << endl;
4258 o << "//" << endl;
4259 o << "// Only one simple format is currently available" << endl;
4260 o << "//" << endl;
4261 o << "// Automatically generated file, do not edit!" << endl;
4262 o << "//" << endl;
4263 o << "" << endl;
4264 o << "class InstTCE<dag outOps, dag inOps, string asmstr," << endl;
4265 o << " list<dag> pattern = []," << endl;
4266 o << " InstrItinClass itin = IT_FU>" << endl;
4267 o << " : Instruction {" << endl;
4268 o << " let Namespace = \"TCE\";" << endl;
4269 o << " dag InOperandList = inOps;" << endl;
4270 o << " dag OutOperandList = outOps;" << endl;
4271 o << " let AsmString = asmstr;" << endl;
4272 o << " let Pattern = pattern;" << endl;
4273 o << " let Itinerary = itin;" << endl;
4274 o << "}" << endl;
4275 o << "" << endl;
4276 o << "class Pseudo<dag outOps, dag inOps," << endl;
4277 o << " string asmstr, list<dag> pattern>" << endl;
4278 o << " : InstTCE<outOps, inOps, asmstr, pattern>;" << endl;
4279}
4280
4281/*
4282 * Operand type characters defined by this TD generator:
4283 * a = Boolean vector
4284 * b = Boolean/predicate register
4285 * c
4286 * d
4287 * e = Float vector register
4288 * f = Float32 register
4289 * g = Half float vector register
4290 * h = Float16 register
4291 * i = Immediate integer
4292 * j = immediate boolean
4293 * k = immediate float?
4294 * l = immediate float16?
4295 * p
4296 * q
4297 * r = integer Register
4298 * s
4299 * t
4300 * u
4301 * y
4302 * z
4303 */
4304/**
4305 * Writes scalar operation definition(s).
4306 *
4307 * @param o Output stream to write the definition to.
4308 * @param op Operation to write definition for.
4309 * @param skipPattern True, if skip pattern generation.
4310 */
4311void
4313 std::ostream& o,
4314 Operation& op,
4315 bool skipPattern) {
4316
4317 std::string attrs;
4318
4319 // These white listed operations have mayLoad/mayStore flag
4320 // inferred from the llvm pattern and declaring it
4321 // explicitly will display warning in tablegen.
4322 if (op.name() != "LDQ" && op.name() != "LDQU" &&
4323 op.name() != "LDH" && op.name() != "LDHU" &&
4324 op.name() != "LDW" && op.name() != "LDD" &&
4325 op.name() != "STQ" && op.name() != "STH" &&
4326 op.name() != "STW" && op.name() != "STD" &&
4327 op.name() != "ALDQ" && op.name() != "ALDQU" &&
4328 op.name() != "ALDH" && op.name() != "ALDHU" &&
4329 op.name() != "ALDW" && op.name() != "ALDD" &&
4330 op.name() != "ASTQ" && op.name() != "ASTH" &&
4331 op.name() != "ASTW" && op.name() != "ASTD" &&
4332
4333 op.name() != "LD8" && op.name() != "LDU8" &&
4334 op.name() != "LD16" && op.name() != "LDU16" &&
4335 op.name() != "LD32" && op.name() != "LDU32" &&
4336 op.name() != "LD64" &&
4337 op.name() != "ST8" && op.name() != "ST16" &&
4338 op.name() != "ST32" && op.name() != "ST64" &&
4339 op.name() != "ALD8" && op.name() != "ALDU8" &&
4340 op.name() != "ALD16" && op.name() != "ALDU16" &&
4341 op.name() != "ALD32" && op.name() != "ALDU32" &&
4342 op.name() != "ALD64" &&
4343 op.name() != "AST8" && op.name() != "AST16" &&
4344 op.name() != "AST32" && op.name() != "AST64" &&
4345 op.name() != "CAS") {
4346
4347 if (op.readsMemory()) attrs += " mayLoad = 1";
4348 if (op.readsMemory() && op.writesMemory()) attrs += ", ";
4349 if (op.writesMemory()) attrs += " mayStore = 1";
4350 }
4351
4352 // no bool outs for some operatios
4353 if (op.name() == "CFI" || op.name() == "CFIU") {
4354 writeOperationDef(o, op, "rf", attrs, skipPattern);
4355 return;
4356 }
4357
4358 if (op.name() == "CDL" || op.name() == "CDLU") {
4359 writeOperationDef(o, op, "sd", attrs, skipPattern);
4360 return;
4361 }
4362
4363 if (op.name() == "CLD" || op.name() == "CLDU") {
4364 writeOperationDef(o, op, "ds", attrs, skipPattern);
4365 return;
4366 }
4367
4368 // no bool outs for some operatios
4369 if (op.name() == "CFD") {
4370 writeOperationDef(o, op, "df", attrs, skipPattern);
4371 return;
4372 }
4373
4374 // no bool outs for some operatios
4375 if (op.name() == "CDF") {
4376 writeOperationDef(o, op, "fd", attrs, skipPattern);
4377 return;
4378 }
4379
4380 // rotations are allways n x n -> n bits.
4381 if (op.name() == "ROTL" || op.name() == "ROTR" ||
4382 op.name() == "SHL" || op.name() == "SHR" || op.name() == "SHRU") {
4383 writeOperationDefs(o, op, "rrr", attrs, skipPattern);
4384 return;
4385 }
4386
4387 if (op.name() == "SXHW" || op.name() == "SXQW") {
4388 writeOperationDef(o, op, "rr", attrs, skipPattern);
4389 return;
4390 }
4391
4392 if (op.name() == "SXW64" || op.name() == "ZXW64") {
4393 writeOperationDef(o, op, "ss", attrs, skipPattern);
4394 return;
4395 }
4396
4397 // these can have 1-bit inputs
4398 // TODO: this is lacking some 64-bit ops??
4399 if (op.name() == "XOR" || op.name() == "IOR" || op.name() == "AND" ||
4400 op.name() == "ANDN" || op.name() == "ADD" || op.name() == "SUB" ||
4401 op.name() == "XOR64" || op.name() == "IOR64" || op.name() == "AND64") {
4402 writeOperationDefs(o, op, "bbb", attrs, skipPattern);
4403 }
4404
4405 if (op.name() == "SELECT") {
4406 if (!hasConditionalMoves_) {
4407 writeOperationDef(o, op, "rrrb", attrs, skipPattern);
4408 writeOperationDef(o, op, "riib", attrs, skipPattern);
4409 writeOperationDef(o, op, "rrib", attrs, skipPattern);
4410 writeOperationDef(o, op, "rirb", attrs, skipPattern);
4411 writeOperationDef(o, op, "bbbb", attrs, skipPattern);
4412 writeOperationDef(o, op, "bjjb", attrs, skipPattern);
4413 writeOperationDef(o, op, "bjbb", attrs, skipPattern);
4414 writeOperationDef(o, op, "bbjb", attrs, skipPattern);
4415 // TODO: what about floating-point values?
4416 writeOperationDef(o, op, "fffb", attrs, skipPattern);
4417 writeOperationDef(o, op, "hhhb", attrs, skipPattern);
4418
4419 // ADFs with boolan values in GPRs
4420 writeOperationDef(o, op, "rrrr", attrs, skipPattern);
4421 writeOperationDef(o, op, "riir", attrs, skipPattern);
4422 writeOperationDef(o, op, "rrir", attrs, skipPattern);
4423 writeOperationDef(o, op, "rirr", attrs, skipPattern);
4424 writeOperationDef(o, op, "bbbr", attrs, skipPattern);
4425 writeOperationDef(o, op, "bjjr", attrs, skipPattern);
4426 writeOperationDef(o, op, "bjbr", attrs, skipPattern);
4427 writeOperationDef(o, op, "bbjr", attrs, skipPattern);
4428 // TODO: what about floating-point values?
4429 writeOperationDef(o, op, "fffr", attrs, skipPattern);
4430 writeOperationDef(o, op, "hhhr", attrs, skipPattern);
4431
4432 hasSelect_ = true;
4433 return;
4434 } else {
4435 std::cerr << "The target architecture has both"
4436 << "conditional moves and select instruction."
4437 << "Ignoring select and using conditional moves instead"
4438 << std::endl;
4439 return;
4440 }
4441 }
4442
4443 // store likes this. store immediate to immediate address
4444 if (op.numberOfInputs() == 2 && op.numberOfOutputs() == 0) {
4445 Operand& operand1 = op.operand(1);
4446 Operand& operand2 = op.operand(2);
4447 /// @note This todo marking is from TDGen.
4448 // TODO: add an else branch here for float immediates
4449 if ((operand1.type() == Operand::UINT_WORD ||
4450 operand1.type() == Operand::SINT_WORD ||
4451 operand1.type() == Operand::RAW_DATA) &&
4452 (operand2.type() == Operand::UINT_WORD ||
4453 operand2.type() == Operand::SINT_WORD ||
4454 operand2.type() == Operand::RAW_DATA)) {
4455
4456 if (mach_.is64bit()) {
4457 writeOperationDef(o, op, "aa", attrs, skipPattern);
4458 } else {
4459 writeOperationDef(o, op, "ii", attrs, skipPattern);
4460 }
4461 }
4462 }
4463
4464 std::string operandTypes = createDefaultOperandTypeString(op);
4465 // this the ordinary def
4466
4467 // then try with immediates.
4468 /// @note This todo marking is from TDGen.
4469 // TODO: this should be 2^n loop instead of n loop, to get
4470 // all permutations.
4471
4472 writeOperationDefs(o, op, operandTypes, attrs, skipPattern);
4473
4474 // then with boolean outs, and vector versions.
4475 if (op.numberOfOutputs() == 1 && !op.readsMemory()) {
4476 Operand& outOperand = op.operand(op.numberOfInputs()+1);
4477 if (outOperand.type() == Operand::UINT_WORD ||
4478 outOperand.type() == Operand::SINT_WORD ||
4479 outOperand.type() == Operand::ULONG_WORD ||
4480 outOperand.type() == Operand::SLONG_WORD) {
4481
4482 // 32/64 to 1-bit operations
4483 operandTypes[0] = OT_REG_BOOL;
4484 writeOperationDefs(o, op, operandTypes, attrs, skipPattern);
4485 }
4486
4487 // create vector versions.
4488 }
4489}
4490
4492 switch(c) {
4493 case TDGen::OT_REG_LONG:
4494 return TDGen::OT_IMM_LONG;
4495 case TDGen::OT_REG_INT:
4496 return TDGen::OT_IMM_INT;
4497 case TDGen::OT_REG_BOOL:
4498 return TDGen::OT_IMM_BOOL;
4499 case TDGen::OT_REG_FP:
4500 return TDGen::OT_IMM_FP;
4501 case TDGen::OT_REG_HFP:
4502 return TDGen::OT_IMM_HFP;
4503 default:
4504 return 0;
4505 }
4506}
4507
4508/**
4509 * Writes operation defs for single operation, with different immediate params.
4510 *
4511 * @param o Output stream to write the definition to.
4512 * @param op Operation to write definition for.
4513 * @param operandTypes value types of operands.
4514 */
4515void
4517 std::ostream& o, Operation& op, const std::string& operandTypes,
4518 const std::string& attrs, bool skipPattern, std::string backendPrefix) {
4519
4520 // first without imms.
4521 writeOperationDef(o, op, operandTypes, attrs, skipPattern, backendPrefix);
4522
4523 for (int i = 0; i < op.numberOfInputs(); i++) {
4524 bool canSwap = false;
4525
4526 // those ops SHOULD be can-swap but are not. kludge-fix.
4527 // consider making them can-swap.
4528 if (op.name() == "ALDQ" || op.name() == "ALDQU" ||
4529 op.name() == "ALDH" || op.name() == "ALDHU" ||
4530 op.name() == "ALDW" || op.name() == "ALDD" ||
4531 op.name() == "ASTQ" || op.name() == "ASTH" ||
4532 op.name() == "ASTW" || op.name() == "ASTD" ||
4533
4534 op.name() == "ALD8" || op.name() == "ALDU8" ||
4535 op.name() == "ALD16"|| op.name() == "ALDU16" ||
4536 op.name() == "ALD32"|| op.name() == "ALD64" ||
4537 op.name() == "AST8" || op.name() == "AST16" ||
4538 op.name() == "AST32"|| op.name() == "AST64") {
4539 canSwap = true;
4540 }
4541
4542 for (int j = i+1 ; j < op.numberOfInputs(); j++) {
4543 if (op.canSwap(i+1, j+1)) {
4544 canSwap = true;
4545 break;
4546 }
4547 }
4548 // setcc of LLVM is not commutative and get confused if we don't generate
4549 // a pattern with immediate elsewhere than the last operand
4550 canSwap = canSwap && !(op.name().upper() == "EQ" || op.name().upper() == "NE");
4551
4552 if (!canSwap) {
4553 std::string opTypes = operandTypes;
4554 char& c = opTypes[i + op.numberOfOutputs()];
4556 if (c) {
4557 writeOperationDef(o, op, opTypes, attrs, skipPattern, backendPrefix);
4558 }
4559 }
4560 }
4561}
4562
4563
4564/**
4565 * Writes special store patterns for i1 types.
4566 */
4567void
4569 std::string storeOp("");
4570 auto storeOps = littleEndian_
4571 ? std::vector<std::string>{"ST8ri", "ST8rr"}
4572 : std::vector<std::string>{"STQri", "STQrr"};
4573 for (auto op : storeOps) {
4574 if (opNames_.count(op)) {
4575 storeOp = op;
4576 break;
4577 }
4578 }
4579 if (storeOp.empty()) return;
4580
4581 // TODO: is this 32 correct for 64-bit ADFs?
4582 auto storeConstBit = [=](const std::string& bitVal) -> std::string {
4583 return std::string("(") + storeOp + " ADDRrr:$addr, " +
4584 (storeOp.back() == 'i' ? "(i32 " : "(MOVI32ri ") + bitVal +
4585 "))";
4586 };
4587
4588 // Patterns to avoid i1 "true" values to be emitted as -1, which breaks
4589 // on, for example, BZ and BNZ if the condition is loaded later, inverted
4590 // using XOR and finally the result is bypassed: this results the -1 to be
4591 // converted to -2, which is interpreted still as true.
4592 os << "def : Pat<(store (i1 -1), ADDRrr:$addr), " << std::endl
4593 << " " << storeConstBit("1") << ">;" << std::endl;
4594 os << "def : Pat<(store (i1 1), ADDRrr:$addr), " << std::endl
4595 << " " << storeConstBit("1") << ">;" << std::endl;
4596 os << "def : Pat<(store (i1 0), ADDRrr:$addr), " << std::endl
4597 << " " << storeConstBit("0") << ">;" << std::endl;
4598}
4599
4600/**
4601 * Writes single immediate operand definitions to the stream.
4602 *
4603 * @param o The output stream.
4604 * @param defName The name of the immediate operand definition.
4605 * @param operandType The target type (i.e "i32").
4606 * @param predicate The predicate expression without return statement or ';'
4607 * at the end.
4608 */
4609void
4611 std::ostream& o,
4612 const std::string& defName,
4613 const std::string& operandType,
4614 const std::string& predicate) {
4615
4616 o << "def " << defName << " : Operand<" << operandType
4617 << "> , ImmLeaf<" << operandType << ", [{" << std::endl
4618 << " return " << predicate << ";}]>;" << std::endl;
4619}
4620
4621/**
4622 * Writes LLVM instruction definition in TCE format to the stream.
4623 *
4624 */
4625void
4627 std::ostream& o,
4628 const std::string& instrDefName,
4629 const std::string& outs,
4630 const std::string& ins,
4631 const std::string& asmString,
4632 const std::string& pattern) {
4633
4634 o << "def " << instrDefName << " : InstTCE<" << std::endl
4635 << " (outs " << outs << ")," << std::endl
4636 << " (ins " << ins << ")," << std::endl
4637 << " \"" << asmString << "\", " << std::endl
4638 << " [" << pattern << "]>;" << std::endl;
4639}
4640
4641/**
4642 * Writes a single operation def for single operation.
4643 *
4644 * @param o Output stream to write the definition to.
4645 * @param op Operation to write definition for.
4646 * @param operandTypes value types of operands.
4647 */
4648void
4650 std::ostream& o,
4651 Operation& op, const std::string& operandTypes, const std::string& attrs,
4652 bool skipPattern, std::string backendPrefix) {
4653 assert (operandTypes.size() > 0);
4654
4655 // Skip definition if the operation has immediate to operand which the
4656 // machine can not transport short immediates to.
4657 if (!areImmediateOperandsLegal(op, operandTypes)) {
4661 << "Skipped writing operation pattern for: "
4662 << op.name() + operandTypes
4663 << ": Can not have immediate operand."
4664 << std::endl;
4665 }
4666 return;
4667 }
4668
4670
4671 std::string outputs, inputs, asmstr, pattern;
4672 outputs = "(outs" + patOutputs(op, operandTypes) + ")";
4673 inputs = "(ins " + patInputs(op, operandTypes) + ")";
4674 std::string predicatedInputs =
4675 "(ins GuardRegs:$pred, " +patInputs(op, operandTypes)+ ")";
4676
4677 asmstr = "\"\"";
4678
4679 if (!skipPattern) {
4680 if (llvmOperationPattern(op, operandChar) != "" ||
4681 op.dagCount() == 0) {
4682 OperationDAG* trivial = createTrivialDAG(op);
4683 pattern = operationPattern(op, *trivial, operandTypes);
4684 delete trivial;
4685 } else {
4686 auto* dagToUse = getMatchableOperationDAG(op);
4687 if (dagToUse)
4688 pattern = operationPattern(op, *dagToUse, operandTypes);
4689 }
4690 }
4691
4692 if (attrs != "") {
4693 o << "let" << attrs << " in { " << std::endl;
4694 }
4695
4696 std::string opcEnum =
4697 StringTools::stringToUpper(op.name()) + operandTypes;
4698
4699 o << "def " << opcEnum << " : "
4700 << "InstTCE<"
4701 << outputs << ", "
4702 << inputs << ", "
4703 << asmstr << ", " ;
4704 if(operandTypes[0] == 'b') { //instruction can be used for comparison
4705 o << "[" << pattern << "]>"
4706 << std::endl
4707 << "{ let isCompare = 1;}" << std::endl;
4708 } else {
4709 o << "[" << pattern << "]>;"
4710 << std::endl;
4711 }
4712
4713 bool opCanBePredicated = canBePredicated(op, operandTypes);
4714
4715 if (opCanBePredicated) {
4716 // write predicated versions
4717 o << "def PRED_TRUE_" << opcEnum << " : "
4718 << "InstTCE<"
4719 << outputs << ", "
4720 << predicatedInputs << ", "
4721 << asmstr << ", "
4722 << "[]>;"
4723 << std::endl;
4724 // write predicated versions
4725 o << "def PRED_FALSE_" << opcEnum << " : "
4726 << "InstTCE<"
4727 << outputs << ", "
4728 << predicatedInputs << ", "
4729 << asmstr << ", "
4730 << "[]>;"
4731 << std::endl;
4732 }
4733
4734 if (attrs != "") {
4735 o << "}" << std::endl;
4736 }
4737 opNames_[opcEnum] = backendPrefix + op.name();
4738
4739 if (opCanBePredicated) {
4740 opNames_["PRED_TRUE_" + opcEnum] = "?" + backendPrefix + op.name();
4741 opNames_["PRED_FALSE_" + opcEnum] = "!" + backendPrefix + op.name();
4742 truePredOps_[opcEnum] = "PRED_TRUE_" + opcEnum;
4743 falsePredOps_[opcEnum] = "PRED_FALSE_" + opcEnum;
4744 }
4745}
4746
4747/**
4748 *
4749 * Returns corresponding character for given operand type.
4750 *
4751 * @param operand Operand under inspection.
4752 * @return Corresponding character of operand type.
4753 */
4754char
4756 if (operand.isVector()) {
4757 if (operand.type() == Operand::BOOL) {
4758 return OT_VREG_BOOL;
4759 } else if (operand.type() == Operand::HALF_FLOAT_WORD) {
4760 return OT_VREG_HFP;
4761 } else if (operand.type() == Operand::FLOAT_WORD) {
4762 return OT_VREG_FP;
4763 } else {
4764 if (operand.elementWidth() == 1) {
4765 return OT_VREG_BOOL;
4766 } else if (operand.elementWidth() == 8) {
4767 return OT_VREG_INT8;
4768 } else if (operand.elementWidth() == 16) {
4769 return OT_VREG_INT16;
4770 } else {
4771 return OT_VREG_INT32;
4772 }
4773 }
4774 }
4775
4776 if (operand.type() == Operand::BOOL) {
4777 return OT_REG_BOOL;
4778 } else if (operand.type() == Operand::HALF_FLOAT_WORD) {
4779 return OT_REG_HFP;
4780 } else if (operand.type() == Operand::ULONG_WORD ||
4781 operand.type() == Operand::SLONG_WORD ||
4782 operand.type() == Operand::RAW_DATA) {
4783 return mach_.is64bit() ? OT_REG_LONG : OT_REG_INT;
4784 } else if (operand.type() != Operand::UINT_WORD &&
4785 operand.type() != Operand::SINT_WORD) {
4786 return OT_REG_FP;
4787 } else {
4788 return OT_REG_INT;
4789 }
4790}
4791
4792/**
4793 * Writes operation emulation pattern in .td format to an output stream.
4794 *
4795 * @param o Output stream to write the definition to.
4796 * @param op Emulated operation.
4797 * @param dag Emulation pattern.
4798 */
4799void
4801 std::ostream& o,
4802 const Operation& op,
4803 const OperationDAG& dag) {
4804
4805 char operandCh = mach_.is64bit() ? OT_REG_LONG : OT_REG_INT;
4806
4807 const OperationDAGNode* res = *(dag.endNodes().begin());
4808 if (dag.endNodes().empty()) {
4809 std::cerr << "end nodes of dag for operation: " << op.name()
4810 << " is empty!" << std::endl;
4811 assert(false);
4812 }
4813
4814 const OperationNode* opNode = dynamic_cast<const OperationNode*>(res);
4815 if (opNode == NULL) {
4816 assert(dag.inDegree(*res) == 1);
4817 const OperationDAGEdge& edge = dag.inEdge(*res, 0);
4818 res = dynamic_cast<OperationNode*>(&dag.tailNode(edge));
4819 assert(res != NULL);
4820 }
4821
4822 int inputCount = op.numberOfInputs();
4823
4824 bool ok = true;
4825 std::string llvmPat = llvmOperationPattern(op, operandCh);
4826 if (llvmPat == "") {
4827 std::cerr << "unknown op: " << op.name() << std::endl;
4828 }
4829 assert(llvmPat != "" && "Unknown operation to emulate.");
4830
4831 boost::format match1(llvmPat);
4832
4833 int outputs = op.numberOfOutputs();
4834
4835 std::string operandTypes;
4836 for (int i = 0; i < outputs; i++) {
4837 operandTypes += operandChar(op.operand(i+inputCount + 1));
4838 }
4839
4840 for (int i = 0; i < op.numberOfInputs(); i++) {
4841 char inputType = operandChar(op.operand(i+1));
4842
4843 std::string immDef = immediateOperandNameForEmulatedOperation(
4844 dag, op.operand(i + 1));
4845
4846 operandTypes += inputType;
4847 match1 % operandToString(op.operand(i + 1), false, inputType, immDef);
4848 }
4849 if (ok) {
4850 o << "def : Pat<(" << match1.str() << "), "
4851 << dagNodeToString(op, dag, *res, true, operandTypes)
4852 << ">;" << std::endl;
4853
4854 // need to generate emulation patterns for boolean out
4855 // for these comparison operations.
4856 if (op.name() == "LTF" || op.name() == "LTUF" ||
4857 op.name() == "EQF" || op.name() == "EQUF" ||
4858 op.name() == "GEF" || op.name() == "GEUF" ||
4859 op.name() == "LEF" || op.name() == "LEUF" ||
4860 op.name() == "GTF" || op.name() == "GTUF" ||
4861 op.name() == "NEF" || op.name() == "NEUF" ||
4862 op.name() == "EQ" || op.name() == "NE" ||
4863 op.name() == "EQ64" || op.name() == "NE64" ||
4864 op.name() == "GE" ||op.name() == "GEU" ||
4865 op.name() == "GE64" ||op.name() == "GEU64" ||
4866 op.name() == "GT" || op.name() == "GTU" ||
4867 op.name() == "GT64" || op.name() == "GTU64" ||
4868 op.name() == "LE" || op.name() == "LEU" ||
4869 op.name() == "LE64" || op.name() == "LEU64" ||
4870 op.name() == "LT" || op.name() == "LTU" ||
4871 op.name() == "LT64" || op.name() == "LTU64" ||
4872 op.name() == "LTD" || op.name() == "LTUD" ||
4873 op.name() == "EQD" || op.name() == "EQUD" ||
4874 op.name() == "GED" || op.name() == "GEUD" ||
4875 op.name() == "LED" || op.name() == "LEUD" ||
4876 op.name() == "GTD" || op.name() == "GTUD" ||
4877 op.name() == "NED" || op.name() == "NEUD" ||
4878 op.name() == "ORDD" || op.name() == "UORDD" ||
4879 op.name() == "ORDF" || op.name() == "UORDF") {
4880 std::string boolOperandTypes = operandTypes;
4881 boolOperandTypes[0] = 'b';
4882 o << "def : Pat<(" << match1.str() << "), "
4883 << dagNodeToString(op, dag, *res, true, boolOperandTypes)
4884 << ">;" << std::endl;
4885 }
4886 }
4887}
4888/**
4889 * Returns LLVM operation pattern for given OSAL operation.
4890 *
4891 * @param op Operation for which the LLVM pattern should be returned.
4892 * @return Operation pattern in llvm.
4893 */
4895TDGen::llvmOperationPattern(const Operation& op, char /*operandType*/) const {
4897
4898 if (opName == "add") return "add %1%, %2%";
4899 if (opName == "add64") return "add %1%, %2%";
4900 if (opName == "sub") return "sub %1%, %2%";
4901 if (opName == "sub64") return "sub %1%, %2%";
4902 if (opName == "mul") return "mul %1%, %2%";
4903 if (opName == "mul64") return "mul %1%, %2%";
4904 if (opName == "div") return "sdiv %1%, %2%";
4905 if (opName == "divu") return "udiv %1%, %2%";
4906 if (opName == "div64") return "sdiv %1%, %2%";
4907 if (opName == "divu64") return "udiv %1%, %2%";
4908 if (opName == "mod") return "srem %1%, %2%";
4909 if (opName == "modu") return "urem %1%, %2%";
4910 if (opName == "mod64") return "srem %1%, %2%";
4911 if (opName == "modu64") return "urem %1%, %2%";
4912
4913 if (opName == "shl") return "shl %1%, %2%";
4914 if (opName == "shr") return "sra %1%, %2%";
4915 if (opName == "shru") return "srl %1%, %2%";
4916 if (opName == "rotl") return "rotl %1%, %2%";
4917 if (opName == "rotr") return "rotr %1%, %2%";
4918
4919
4920 if (opName == "shl64") return "shl %1%, %2%";
4921 if (opName == "shr64") return "sra %1%, %2%";
4922 if (opName == "shru64") return "srl %1%, %2%";
4923 if (opName == "rotl64") return "rotl %1%, %2%";
4924 if (opName == "rotr64") return "rotr %1%, %2%";
4925
4926 if (opName == "and") return "and %1%, %2%";
4927 if (opName == "ior") return "or %1%, %2%";
4928 if (opName == "xor") return "xor %1%, %2%";
4929
4930 if (opName == "and64") return "and %1%, %2%";
4931 if (opName == "ior64") return "or %1%, %2%";
4932 if (opName == "xor64") return "xor %1%, %2%";
4933
4934 if (opName == "eq") return "seteq %1%, %2%";
4935 if (opName == "eq64") return "seteq %1%, %2%";
4936 if (opName == "ne") return "setne %1%, %2%";
4937 if (opName == "ne64") return "setne %1%, %2%";
4938 if (opName == "lt") return "setlt %1%, %2%";
4939 if (opName == "lt64") return "setlt %1%, %2%";
4940 if (opName == "le") return "setle %1%, %2%";
4941 if (opName == "le64") return "setle %1%, %2%";
4942 if (opName == "gt") return "setgt %1%, %2%";
4943 if (opName == "gt64") return "setgt %1%, %2%";
4944 if (opName == "ge") return "setge %1%, %2%";
4945 if (opName == "ge64") return "setge %1%, %2%";
4946 if (opName == "ltu") return "setult %1%, %2%";
4947 if (opName == "ltu64") return "setult %1%, %2%";
4948 if (opName == "leu") return "setule %1%, %2%";
4949 if (opName == "leu64") return "setule %1%, %2%";
4950 if (opName == "gtu") return "setugt %1%, %2%";
4951 if (opName == "gtu64") return "setugt %1%, %2%";
4952 if (opName == "geu") return "setuge %1%, %2%";
4953 if (opName == "geu64") return "setuge %1%, %2%";
4954
4955 if (opName == "eqf" || opName == "eqd") return "setoeq %1%, %2%";
4956 if (opName == "nef" || opName == "ned") return "setone %1%, %2%";
4957 if (opName == "ltf" || opName == "ltd") return "setolt %1%, %2%";
4958 if (opName == "lef" || opName == "led") return "setole %1%, %2%";
4959 if (opName == "gtf" || opName == "gtd") return "setogt %1%, %2%";
4960 if (opName == "gef" || opName == "ged") return "setoge %1%, %2%";
4961
4962 if (opName == "equf" || opName == "equd") return "setueq %1%, %2%";
4963 if (opName == "neuf" || opName == "neud") return "setune %1%, %2%";
4964 if (opName == "ltuf" || opName == "ltud") return "setult %1%, %2%";
4965 if (opName == "leuf" || opName == "leud") return "setule %1%, %2%";
4966 if (opName == "gtuf" || opName == "gtud") return "setugt %1%, %2%";
4967 if (opName == "geuf" || opName == "geud") return "setuge %1%, %2%";
4968
4969 if (opName == "ordf" || opName == "ordd") return "seto %1%, %2%";
4970 if (opName == "uordf"|| opName == "uordd")return "setuo %1%, %2%";
4971
4972 if (opName == "addf" || opName == "addd") return "fadd %1%, %2%";
4973 if (opName == "subf" || opName == "subd") return "fsub %1%, %2%";
4974 if (opName == "mulf" || opName == "muld") return "fmul %1%, %2%";
4975 if (opName == "divf" || opName == "divd") return "fdiv %1%, %2%";
4976 if (opName == "absf" || opName == "absd") return "fabs %1%";
4977 if (opName == "negf" || opName == "negd") return "fneg %1%";
4978 if (opName == "sqrtf"|| opName == "sqrtd")return "fsqrt %1%";
4979
4980 if (opName == "cif") return "sint_to_fp %1%";
4981 if (opName == "cfi") return "fp_to_sint %1%";
4982 if (opName == "cifu") return "uint_to_fp %1%";
4983 if (opName == "cfiu") return "fp_to_uint %1%";
4984
4985 if (opName == "cld") return "sint_to_fp %1%";
4986 if (opName == "cdl") return "fp_to_sint %1%";
4987 if (opName == "cldu") return "uint_to_fp %1%";
4988 if (opName == "cdlu") return "fp_to_uint %1%";
4989
4990 if (opName == "cfh" || opName == "cdf") return "fpround %1%";
4991 if (opName == "chf") return "f32 (fpextend %1%)";
4992 if (opName == "cfd") return "f64 (fpextend %1%)";
4993
4994 if (opName == "cih") return "sint_to_fp %1%";
4995 if (opName == "chi") return "i32 (fp_to_sint %1%)";
4996 if (opName == "cihu") return "uint_to_fp %1%";
4997 if (opName == "chiu") return "i32 (fp_to_uint %1%)";
4998
4999 if (opName == "neuh") return "setune %1%, %2%";
5000 if (opName == "eqh") return "setoeq %1%, %2%";
5001 if (opName == "neh") return "setone %1%, %2%";
5002 if (opName == "lth") return "setolt %1%, %2%";
5003 if (opName == "leh") return "setole %1%, %2%";
5004 if (opName == "gth") return "setogt %1%, %2%";
5005 if (opName == "geh") return "setoge %1%, %2%";
5006
5007 if (opName == "ordh") return "seto %1%, %2%";
5008 if (opName == "uordh") return "setuo %1%, %2%";
5009
5010 if (opName == "addh") return "fadd %1%, %2%";
5011 if (opName == "subh") return "fsub %1%, %2%";
5012 if (opName == "mulh") return "fmul %1%, %2%";
5013 if (opName == "divh") return "fdiv %1%, %2%";
5014 if (opName == "absh") return "fabs %1%";
5015 if (opName == "negh") return "fneg %1%";
5016 if (opName == "sqrth") return "fsqrt %1%";
5017
5018 if (opName == "cih") return "sint_to_fp %1%";
5019 if (opName == "chi") return "fp_to_sint %1%";
5020 if (opName == "cihu") return "uint_to_fp %1%";
5021 if (opName == "chiu") return "fp_to_uint %1%";
5022
5023 if (opName == "csh") return "sint_to_fp %1%";
5024 if (opName == "cshu") return "uint_to_fp %1%";
5025 if (opName == "chs") return "fp_to_sint %1%";
5026 if (opName == "chsu") return "fp_to_uint %1%";
5027
5028 if (littleEndian_) {
5029 if (opName == "ld8") return "sextloadi8 %1%";
5030 if (opName == "ldu8") return "zextloadi8 %1%";
5031 if (opName == "ld16") return "sextloadi16 %1%";
5032 if (opName == "ldu16") return "zextloadi16 %1%";
5033 if (mach_.is64bit()) {
5034 if (opName == "ld32") return "sextloadi32 %1%";
5035 if (opName == "ldu32") return "zextloadi32 %1%";
5036 } else {
5037 if (opName == "ld32" || opName == "ldu32") return "load %1%";
5038 }
5039 if (opName == "ld64") return "load %1%";
5040 //if (opName == "ldd") return "load";
5041
5042 if (opName == "st8") return "truncstorei8 %2%, %1%";
5043 if (opName == "st16") return "truncstorei16 %2%, %1%";
5044 if (mach_.is64bit()) {
5045 if (opName == "st32") return "truncstorei32 %2%, %1%";
5046 } else {
5047 if (opName == "st32") return "store %2%, %1%";
5048 }
5049 if (opName == "st64") return "store %2%, %1%";
5050 } else {
5051 if (opName == "ldq") return "sextloadi8 %1%";
5052 if (opName == "ldqu") return "zextloadi8 %1%";
5053 if (opName == "ldh") return "sextloadi16 %1%";
5054 if (opName == "ldhu") return "zextloadi16 %1%";
5055 if (opName == "ldw") return "load %1%";
5056 //if (opName == "ldd") return "load";
5057
5058 if (opName == "stq") return "truncstorei8 %2%, %1%";
5059 if (opName == "sth") return "truncstorei16 %2%, %1%";
5060 if (opName == "stw") return "store %2%, %1%";
5061 //if (opName == "std") return "load";
5062 }
5063
5064 if (opName == "sxw64") {
5065 return "sext_inreg %1%, i32";
5066 }
5067
5068 if (opName == "sxb64") {
5069 return "sext_inreg %1%, i1";
5070 }
5071
5072 if (opName == "sxq64") {
5073 return "sext_inreg %1%, i8";
5074 }
5075 if (opName == "sxh64") {
5076 return "sext_inreg %1%, i16";
5077 }
5078
5079 if (opName == "sxhw") {
5080 return "sext_inreg %1%, i16";
5081 }
5082 if (opName == "sxqw") {
5083 return "sext_inreg %1%, i8";
5084 }
5085
5086 if (opName == "sxw")
5087 return mach_.is64bit() ? "sext_inreg %1%, i64": "sext_inreg %1%, i32";
5088
5089 if (opName == "sxbw") return "sext_inreg %1%, i1";
5090
5091 if (opName == "truncwh" || opName == "truncwb" || opName == "trunchb")
5092 return "trunc %1%";
5093
5094 if (opName == "neg") return "ineg %1%";
5095 if (opName == "not") return "not %1%";
5096
5097 if (opName == "cas") return "atomic_cmp_swap_32 %1%, %2%, %3%";
5098 if (opName == "select") return "select %3%, %1%, %2%";
5099
5100 // Unknown operation name.
5101 return "";
5102}
5103
5104/**
5105 * Returns llvm operation name for the given OSAL operation name, if any.
5106 */
5107
5109TDGen::llvmOperationName(const TCEString& operationName) const {
5110
5111 TCEString opName = StringTools::stringToLower(operationName);
5112
5113 if (opName == "add") return "add";
5114 if (opName == "sub") return "sub";
5115 if (opName == "mul") return "mul";
5116 if (opName == "div") return "sdiv";
5117 if (opName == "divu") return "udiv";
5118 if (opName == "mod") return "srem";
5119 if (opName == "modu") return "urem";
5120
5121 if (opName == "add64") return "add";
5122 if (opName == "sub64") return "sub";
5123 if (opName == "mul64") return "mul";
5124 if (opName == "div64") return "sdiv";
5125 if (opName == "divu64") return "udiv";
5126 if (opName == "mod64") return "srem";
5127 if (opName == "modu64") return "urem";
5128
5129 if (opName == "shl") return "shl";
5130 if (opName == "shr") return "sra";
5131 if (opName == "shru") return "srl";
5132 if (opName == "rotl") return "rotl";
5133 if (opName == "rotr") return "rotr";
5134
5135 if (opName == "shl64") return "shl";
5136 if (opName == "shr64") return "sra";
5137 if (opName == "shru64") return "srl";
5138 if (opName == "rotl64") return "rotl";
5139 if (opName == "rotr64") return "rotr";
5140
5141 if (opName == "and") return "and";
5142 if (opName == "ior") return "or";
5143 if (opName == "xor") return "xor";
5144
5145 if (opName == "and64") return "and";
5146 if (opName == "ior64") return "or";
5147 if (opName == "xor64") return "xor";
5148
5149 if (opName == "eq") return "seteq";
5150 if (opName == "eq64") return "seteq";
5151 if (opName == "ne") return "setne";
5152 if (opName == "ne64") return "setne";
5153 if (opName == "lt") return "setlt";
5154 if (opName == "lt64") return "setlt";
5155 if (opName == "le") return "setle";
5156 if (opName == "le64") return "setle";
5157 if (opName == "gt") return "setgt";
5158 if (opName == "gt64") return "setgt";
5159 if (opName == "ge") return "setge";
5160 if (opName == "ltu") return "setult";
5161 if (opName == "ltu64") return "setult";
5162 if (opName == "leu") return "setule";
5163 if (opName == "leu64") return "setule";
5164 if (opName == "gtu") return "setugt";
5165 if (opName == "gtu64") return "setugt";
5166 if (opName == "geu") return "setuge";
5167 if (opName == "geu64") return "setuge";
5168
5169 if (opName == "eqf" || opName == "eqd") return "setoeq";
5170 if (opName == "nef" || opName == "ned") return "setone";
5171 if (opName == "ltf" || opName == "ltd") return "setolt";
5172 if (opName == "lef" || opName == "led") return "setole";
5173 if (opName == "gtf" || opName == "gtd") return "setogt";
5174 if (opName == "gef" || opName == "ged") return "setoge";
5175
5176 if (opName == "equf" || opName == "equd") return "setueq";
5177 if (opName == "neuf" || opName == "neud") return "setune";
5178 if (opName == "ltuf" || opName == "ltud") return "setult";
5179 if (opName == "leuf" || opName == "leud") return "setule";
5180 if (opName == "gtuf" || opName == "gtud") return "setugt";
5181 if (opName == "geuf" || opName == "geud") return "setuge";
5182
5183 if (opName == "ordf" || opName =="ordd") return "seto";
5184 if (opName == "uordf" || opName == "uordd") return "setuo";
5185
5186 if (opName == "addf") return "fadd";
5187 if (opName == "subf") return "fsub";
5188 if (opName == "mulf") return "fmul";
5189 if (opName == "divf") return "fdiv";
5190 if (opName == "absf") return "fabs";
5191 if (opName == "negf") return "fneg";
5192 if (opName == "sqrtf") return "fsqrt";
5193
5194 if (opName == "cif") return "sint_to_fp";
5195 if (opName == "cfi") return "fp_to_sint";
5196 if (opName == "cifu") return "uint_to_fp";
5197 if (opName == "cfiu") return "fp_to_uint";
5198
5199 if (opName == "cfh") return "fpround";
5200 if (opName == "chf") return "fpextend";
5201
5202 if (littleEndian_) {
5203 if (opName == "ld8") return "sextloadi8";
5204 if (opName == "ldu8") return "zextloadi8";
5205 if (opName == "ld16") return "sextloadi16";
5206 if (opName == "ldu16") return "zextloadi16";
5207 if (mach_.is64bit()) {
5208 if (opName == "ld32") return "sextloadi32";
5209 if (opName == "ldu32") return "zextloadi32";
5210 } else {
5211 if (opName == "ld32" || opName =="ldu32") return "load";
5212 }
5213 if (opName == "ld64") return "load";
5214
5215 //if (opName == "ldd") return "load";
5216
5217 if (opName == "st8") return "truncstorei8";
5218 if (opName == "st16") return "truncstorei16";
5219 if (opName == "st32") {
5220 if (mach_.is64bit()) {
5221 return "truncstorei32";
5222 } else {
5223 return "store";
5224 }
5225 }
5226
5227 if (opName == "st32") return "store";
5228 if (opName == "st64") return "store";
5229 //if (opName == "std") return "load";
5230 } else { // big-endian
5231 if (opName == "ldq") return "sextloadi8";
5232 if (opName == "ldqu") return "zextloadi8";
5233 if (opName == "ldh") return "sextloadi16";
5234 if (opName == "ldhu") return "zextloadi16";
5235 if (opName == "ldw") return "load";
5236 //if (opName == "ldd") return "load";
5237
5238 if (opName == "stq") return "truncstorei8";
5239 if (opName == "sth") return "truncstorei16";
5240 if (opName == "stw") return "store";
5241 //if (opName == "std") return "load";
5242 }
5243
5244 if (opName.length() >2 && opName.substr(0,2) == "sx") {
5245 return "sext_inreg";
5246 }
5247
5248 if (opName == "truncwh" || opName == "truncwb" || opName == "trunchb")
5249 return "trunc";
5250
5251 if (opName == "neg") return "ineg";
5252 if (opName == "not") return "not";
5253 if (opName == "cas") return "atomic_cmp_swap_32";
5254
5255 if (opName == "select") return "select";
5256
5257 // Unknown operation name.
5258 return "";
5259}
5260
5261
5262/**
5263 * Pattern for tce generated custom op patterns.
5264 */
5265std::string
5267 std::string opList = "";
5268 for (int i = 0; i < op.numberOfInputs(); i++) {
5269 opList += " %" + Conversion::toString(i+1) + "%";
5270 }
5271 return op.name() + opList;
5272}
5273
5274/**
5275 * Check if operation can be matched with llvm pattern.
5276 *
5277 * Check if operation has llvmOperationPatters or
5278 * one of it's DAGs contain only operations, which can be matched.
5279 */
5280bool
5282 const Operation& op, std::set<std::string>* recursionCycleCheck,
5283 bool recursionHasStore) {
5284
5285 // LLVM does not support operations with >255 inputs.
5286 if (op.numberOfInputs() > 255) {
5287 return false;
5288 }
5289 // TODO: this should have been changed?
5291 // if operation has llvm pattern
5292 if (llvmOperationPattern(op,operandChar) != "") {
5293 return true;
5294 }
5295
5296 std::set<std::string> useSet;
5297 if (recursionCycleCheck != NULL) {
5298 useSet = *recursionCycleCheck;
5299 }
5300 useSet.insert(op.name());
5301
5302 // check if one of dags of operation is ok
5303 for (int i = 0; i < op.dagCount(); i++) {
5304 OperationDAG& dag = op.dag(i);
5305 if (operationDAGCanBeMatched(dag, &useSet, recursionHasStore)) {
5306 return true;
5307 }
5308 }
5309
5310 return false;
5311}
5312
5313
5314bool
5316 const OperationDAG& opDag,
5317 std::set<std::string>* recursionCycleCheck,
5318 bool recursionHasStore) {
5319
5320 bool hasStore = false;
5321
5322 for (int j = 0; j < opDag.nodeCount(); j++) {
5323 OperationNode* opNode = dynamic_cast<OperationNode*>(&opDag.node(j));
5324 if (opNode) {
5325 Operation& refOp = opNode->referencedOperation();
5326 if (refOp.writesMemory()) {
5327 if (recursionHasStore || hasStore) {
5328 return false;
5329 } else {
5330 hasStore = true;
5331 }
5332 }
5333
5334 // check that the same operation is not used recursively
5335 if (recursionCycleCheck &&
5336 recursionCycleCheck->count(refOp.name()) != 0) {
5337 return false;
5338 }
5339
5340 // check if referenced op can be matched
5341 if (!operationCanBeMatched(refOp, recursionCycleCheck,
5342 hasStore)) {
5343 return false;
5344 }
5345 }
5346 }
5347 return true;
5348}
5349
5350/**
5351 * Returns first operation DAG that can be used in LLVM pattern.
5352 *
5353 * Operation DAGs are traversed in the order of trigger-semantics in the
5354 * first .opp file found in path that defines the Operation.
5355 *
5356 * This method does not transfer ownership.
5357 *
5358 * @return The matchable operation DAG. Nullptr if could not find.
5359 */
5360const OperationDAG*
5362 const Operation& op) {
5363
5364 // check if one of dags of operation is ok
5365 for (int i = 0; i < op.dagCount(); i++) {
5366 OperationDAG& dag = op.dag(i);
5367 if (op.dagError(i) != "") {
5368 std::cerr << "Broken dag in operation " << op.name()
5369 << op.dagCode(i) << std::endl;
5370 assert(0);
5371 }
5372
5373 if (operationDAGCanBeMatched(dag)) {
5374 return &dag;
5375 }
5376 }
5377 return nullptr;
5378}
5379
5380/**
5381 * Returns a vector of DAGs that can be used in LLVM pattern.
5382 *
5383 * Operation DAGs are traversed in the order of trigger-semantics in the
5384 * first .opp file found in path that defines the Operation.
5385 *
5386 * This method does not transfer ownership.
5387 *
5388 * @return The matchable operation DAGs. Empty if could not find.
5389 */
5390const std::vector<OperationDAG*>
5392 const Operation& op) {
5393 std::vector<OperationDAG*> matchableDAGs;
5394 for (int i = 0; i < op.dagCount(); i++) {
5395 OperationDAG& dag = op.dag(i);
5396 if (op.dagError(i) != "") {
5397 std::cerr << "Broken dag in operation " << op.name()
5398 << op.dagCode(i) << std::endl;
5399 continue;
5400 }
5401
5402 if (operationDAGCanBeMatched(dag)) {
5403 matchableDAGs.push_back(&dag);
5404 }
5405 }
5406 return matchableDAGs;
5407}
5408
5409
5410/**
5411 * Returns operation pattern in llvm .td format.
5412 *
5413 * @param op Operation to return pattern for.
5414 * @param dag Operation pattern's DAG.
5415 * @param immOp Index of an operand to define as an immediate operand,
5416 * or 0, if all operands should be in registers.
5417 *
5418 * @return Pattern string.
5419 */
5420std::string
5422 const Operation& op,
5423 const OperationDAG& dag,
5424 const std::string& operandTypes) {
5425
5426 std::string retVal;
5427 for (OperationDAG::NodeSet::iterator i = dag.endNodes().begin();
5428 i != dag.endNodes().end(); ++i) {
5429 if (i != dag.endNodes().begin()) {
5430 retVal += ",";
5431 }
5432 const OperationDAGNode& res = **(i);
5433 retVal += dagNodeToString(op, dag, res, false, operandTypes);
5434 }
5435 return retVal;
5436}
5437
5438std::string
5440 std::string operandTypes;
5441
5442 int inputs = op.numberOfInputs();
5443 int outputs = op.numberOfOutputs();
5444
5445 for (int i = 0; i < outputs; i++) {
5446 Operand& operand = op.operand(i + inputs +1);
5447 operandTypes += operandChar(operand);
5448 }
5449
5450 for (int i = 0; i < inputs ; i++) {
5451 Operand& operand = op.operand(i +1);
5452 operandTypes += operandChar(operand);
5453 }
5454 return operandTypes;
5455}
5456
5457/**
5458 * Return operation pattern is llvm .td format without outputs.
5459 *
5460 * This pattern can be used as sub-pattern of bigger pattern.
5461 * The operation must have only one output.
5462 *
5463 * @param op Operation to return pattern for.
5464 * @param dag Operation pattern's DAG.
5465 * @return Pattern string.
5466 */
5467std::string
5469 const Operation& op,
5470 const OperationDAG& dag) {
5471
5472 if (dag.endNodes().size() != 1) {
5473 throw InvalidData(
5474 __FILE__,__LINE__,__func__,
5475 "Cannot create subpattern: not exactly 1 end node!");
5476 }
5477
5478 OperationDAG::NodeSet::iterator i = dag.endNodes().begin();
5479 const OperationDAGNode& res = **(i);
5480 OperationDAG::NodeSet preds = dag.predecessors(res);
5481 if (preds.size() != 1) {
5482 throw InvalidData(
5483 __FILE__,__LINE__,__func__,
5484 "Cannot create subpattern: not single data source for end node.");
5485 }
5486
5487 std::string operandTypes = createDefaultOperandTypeString(op);
5488 // TODO: what about immediate operands?
5489
5490 // TODO: size of the operand string?
5491 return dagNodeToString(
5492 op, dag, **(preds.begin()), false, operandTypes);
5493}
5494/**
5495 * Converts single OperationDAG node to llvm pattern fragment string.
5496 *
5497 * @param op Operation that the whole DAG is for.
5498 * @param dag Whole operation DAG.
5499 * @param node DAG node to return string for.
5500 * @param immOp Index of an operand to define as an immediate or 0 if none.
5501 * @param emulationPattern True, if the returned string should be in
5502 * emulation pattern format.
5503 * @return DAG node as a llvm .td string.
5504 */
5505std::string
5507 const Operation& op, const OperationDAG& dag, const OperationDAGNode& node,
5508 bool emulationPattern, const std::string& operandTypes,
5509 const Operation* emulatingOp, const OperationDAGNode* successor) {
5510 const OperationNode* oNode = dynamic_cast<const OperationNode*>(&node);
5511 if (oNode != NULL) {
5512 assert(
5513 dag.inDegree(*oNode) ==
5515
5516 return operationNodeToString(
5517 op, dag, *oNode, emulationPattern, operandTypes);
5518 }
5519
5520 const TerminalNode* tNode = dynamic_cast<const TerminalNode*>(&node);
5521 if (tNode != NULL) {
5522 const Operand& operand = op.operand(tNode->operandIndex());
5523 if (dag.inDegree(*tNode) == 0) {
5524 // Input operand for the whole operation.
5525 assert(operand.isInput());
5526
5527 char operandType =
5528 operandTypes[operand.index()-1 + op.numberOfOutputs()];
5529 bool imm = (operandType == OT_IMM_INT ||
5530 operandType == OT_IMM_BOOL);
5531
5532 if (imm && !canBeImmediate(dag, *tNode)) {
5533 std::string msg =
5534 "Invalid immediate operand for " + op.name() +
5535 " operand #" + Conversion::toString(tNode->operandIndex());
5536 throw InvalidData(__FILE__, __LINE__, __func__, msg);
5537 }
5538
5539 if (emulationPattern) {
5540 assert(emulatingOp != nullptr);
5541 return operandToString(operand, false, operandType,
5543 *emulatingOp, operand)]);
5544 } else {
5545 return operandToString(operand, false, operandType,
5546 immOperandDefs_[ImmInfo::key(op, operand)]);
5547 }
5548 } else {
5549 // Output operand for the whole operation.
5550 assert(dag.inDegree(*tNode) == 1);
5551 assert(op.operand(tNode->operandIndex()).isOutput());
5552 assert(operand.isOutput());
5553 int globalOperandIndex =
5554 tNode->operandIndex() - op.numberOfInputs();
5555 assert(globalOperandIndex == 1);
5556
5557 const OperationDAGEdge& edge = dag.inEdge(node, 0);
5558 const OperationDAGNode& srcNode = dag.tailNode(edge);
5559
5560 // Multiple-output operation nodes not supported in the middle
5561 // of dag:
5562 assert(dag.outDegree(srcNode) == 1);
5563
5564 std::string dnString =
5566 op, dag, srcNode, emulationPattern, operandTypes,
5567 emulatingOp, successor);
5568
5569 bool needTrunc = (operandTypes[globalOperandIndex-1] ==
5570 OT_REG_BOOL &&
5571 operandTypes[1] != OT_REG_BOOL &&
5572 operandTypes[1] != OT_IMM_BOOL);
5573
5574 // handle setcc's without trunc
5575 // also loads and extends.
5576 if (needTrunc) {
5577 if (dnString.substr(0,4) == "(set" ||
5578 dnString.substr(0,5) == "(zext" ||
5579 dnString.substr(0,5) == "(load") {
5580 needTrunc = false;
5581 }
5582 }
5583
5584 if (needTrunc) {
5585 std::string pattern =
5586 "(set " + operandToString(
5587 operand, emulationPattern, operandTypes[0])
5588 + ", (trunc " + dnString + "))";
5589 return pattern;
5590 } else {
5591 std::string pattern =
5592 "(set " + operandToString(
5593 operand, emulationPattern, operandTypes[0])
5594 + ", " + dnString + ")";
5595 return pattern;
5596 }
5597 }
5598 }
5599
5600 // Constant values.
5601 const ConstantNode* cNode = dynamic_cast<const ConstantNode*>(&node);
5602 if (cNode != NULL) {
5603 return constantNodeString(op, dag, *cNode, operandTypes, successor);
5604 }
5605
5606 abortWithError("Unknown OperationDAG node type.");
5607 return "";
5608}
5609
5610std::string
5612 const Operation& op,
5613 const OperationDAG& dag,
5614 const ConstantNode& node,
5615 const std::string& operandTypes,
5616 const OperationDAGNode* successor) {
5617
5618 assert(dag.inDegree(node) == 0);
5619 assert(dag.outDegree(node) == 1 || successor);
5620 const OperationDAGNode& succ = successor ?
5621 *successor : dag.headNode(dag.outEdge(node,0));
5622 const OperationNode* opn = dynamic_cast<const OperationNode*>(&succ);
5623 OperationDAG::NodeSet siblings = dag.predecessors(*opn);
5624 for (OperationDAG::NodeSet::iterator i = siblings.begin();
5625 i!= siblings.end(); i++) {
5626 const TerminalNode* tNode = dynamic_cast<const TerminalNode*>(*i);
5627 if (tNode != NULL) {
5628 const Operand& operand = op.operand(tNode->operandIndex());
5629 assert(operand.isInput());
5630 char operandType =
5631 operandTypes[operand.index()-1 + op.numberOfOutputs()];
5632 // Retrieve largest short immediate for the operand.
5633 switch (operandType) {
5634 case OT_REG_BOOL:
5635 case OT_IMM_BOOL:
5636 return "(i1 " + Conversion::toString(node.value()) + ")";
5637 case OT_REG_DOUBLE:
5638 return "(f64 " + Conversion::toString(node.value()) +")";
5639 case OT_REG_HFP:
5640 return "(f16 " + Conversion::toString(node.value()) + ")";
5641 // TODO: f16 vectors not yet implemented
5642 case OT_REG_FP:
5643 case OT_IMM_FP:
5644 return "(f32 " + Conversion::toString(node.value()) + ")";
5645 case OT_REG_LONG:
5646 case OT_IMM_LONG:
5647 return "(i64 " + Conversion::toString(node.value()) + ")";
5648 case OT_REG_INT:
5649 case OT_IMM_INT:
5650 return mach_.is64bit() ?
5651 "(i64 " + Conversion::toString(node.value()) + ")":
5652 "(i32 " + Conversion::toString(node.value()) + ")";
5653 default:
5654 break;
5655 }
5656 }
5657 }
5658 // TODO: Declaring without type specifier is not valid?
5659 // The constnode would return this if it is the outer most op in the dag
5660 return mach_.is64bit() ?
5661 "(i64 " + Conversion::toString(node.value()) + ")":
5662 "(i32 " + Conversion::toString(node.value()) + ")";
5663}
5664
5665/**
5666 * Returns an llvm name for an operation node in an emulation dag.
5667 *
5668 * @param op the operation being emulated.
5669 * @param dag dag of the emulated operation
5670 * @param node node whose name is being asked
5671 * @param operandTypes string containing oeprand types for the emulated op.
5672 */
5673std::string
5675 const Operation& op, const OperationDAG& dag, const OperationNode& node,
5676 const std::string& operandTypes) {
5677 const Operation& operation = node.referencedOperation();
5678 std::string operationName = StringTools::stringToUpper(operation.name());
5679
5680
5681 int inputs = operation.numberOfInputs();
5682
5683 // Look at outgoing nodes. If operand goes to another op,
5684 // the value is in register.
5685 // if it's terminal, get the type from the paramete string.
5686 for (int i = 1 ; i < operation.numberOfOutputs() + 1; i++) {
5687 char c = 0;
5688 for (int e = 0; e < dag.outDegree(node); e++) {
5689 const OperationDAGEdge& edge = dag.outEdge(node, e);
5690 int dst = edge.srcOperand();
5691 if (dst == i + operation.numberOfInputs()) {
5692 TerminalNode* t =
5693 dynamic_cast<TerminalNode*>(
5694 &(dag.headNode(edge)));
5695 if (t != NULL) {
5696 int strIndex = t->operandIndex() -1 -
5697 op.numberOfInputs();
5698 assert((int)operandTypes.length() > strIndex &&
5699 strIndex >= 0);
5700 if (c != 0 && c != operandTypes[strIndex]) {
5701 throw InvalidData(__FILE__,__LINE__,__func__,
5702 "conflicting output types!");
5703 }
5704 c = operandTypes[strIndex];
5705 } else {
5706 Operand &operand =
5707 operation.operand(i+operation.numberOfInputs());
5708 char type = operandChar(operand);
5709 if (c != 0 && c!= type) {
5710 throw InvalidData(__FILE__,__LINE__,__func__,
5711 "conflicting output types!");
5712 }
5713 c = type;
5714 }
5715 }
5716 }
5717 if (c == 0) {
5718 throw InvalidData(__FILE__,__LINE__,__func__,"output not found.");
5719 }
5720 operationName += c;
5721 }
5722
5723 // Look at incoming nodes. If operand comes from another op,
5724 // the value is in register. If operand comes from constant,
5725 // it's immediate.
5726 // if it's terminal, get the type from the parm string.
5727 for (int i = 1; i < inputs + 1; i++) {
5728 Operand &operand = operation.operand(i);
5729 for (int e = 0; e < dag.inDegree(node); e++) {
5730 const OperationDAGEdge& edge = dag.inEdge(node, e);
5731 int dst = edge.dstOperand();
5732 if (dst == i) {
5733 if (dynamic_cast<OperationNode*>(&(dag.tailNode(edge)))) {
5734 operationName += operandChar(operand);
5735 } else {
5736 if (dynamic_cast<ConstantNode*>(
5737 &(dag.tailNode(edge)))) {
5738 if (operand.type() == Operand::SINT_WORD ||
5739 operand.type() == Operand::UINT_WORD) {
5740 operationName += OT_IMM_INT;
5741 } else if (operand.type() == Operand::RAW_DATA ||
5742 operand.type() == Operand::SLONG_WORD ||
5743 operand.type() == Operand::ULONG_WORD) {
5744 operationName += mach_.is64bit() ?
5746 }
5747 } else {
5748 TerminalNode* t =
5749 dynamic_cast<TerminalNode*>(
5750 &(dag.tailNode(edge)));
5751 assert (t != NULL);
5752 int strIndex = t->operandIndex() -1 +
5753 op.numberOfOutputs();
5754 if ((int)operandTypes.length() <= strIndex ||
5755 strIndex <= 0) {
5756 std::cerr << "Invalid operand types length or"
5757 << "strIndex in operation:"
5758 << operation.name()
5759 << " OperandTypes string is: "
5760 << operandTypes
5761 << " strIndex is: " << strIndex
5762 << std::endl;
5763 assert(false);
5764 }
5765 operationName += operandTypes[strIndex];
5766 }
5767 }
5768 }
5769 }
5770 }
5771 return operationName;
5772}
5773
5774/**
5775 * Converts OSAL dag operation node to llvm .td pattern fragment string.
5776 *
5777 * @param op Operation which this operation node is part of.
5778 * @param dag Parent DAG of the operation node.
5779 * @param node Node to convert to string.
5780 * @param immOp Index of an operand to define as immediate or 0 if none.
5781 * @param emulationPattern True, if the string should be in emulation pattern
5782 * format.
5783 */
5784std::string
5786 const Operation& op, const OperationDAG& dag, const OperationNode& node,
5787 bool emulationPattern, const std::string& operandTypes) {
5788 const Operation& operation = node.referencedOperation();
5789
5790 std::string operationPat;
5791
5792 if (emulationPattern) {
5793 operationPat = emulatingOpNodeLLVMName(
5794 op, dag, node, operandTypes);
5795
5796 for (int i = 0; i < operation.numberOfInputs(); i++) {
5797 if (i > 0) {
5798 operationPat += ", ";
5799 } else {
5800 operationPat += " ";
5801 }
5802 operationPat =
5803 operationPat + "%" + Conversion::toString(i + 1) + "%";
5804 }
5805 } else {
5806 operationPat = llvmOperationPattern(operation, operandTypes[0]);
5807
5808 // generate pattern for operation if not llvmOperation (can match
5809 // custom op patterns)
5810 if (operationPat == "") {
5811 auto* dagToUse = getMatchableOperationDAG(operation);
5812 if (dagToUse) {
5813 return subPattern(operation, *dagToUse);
5814 } else {
5815 operationPat = tceOperationPattern(operation);
5816 }
5817 }
5818 }
5819
5820 if (operationPat == "") {
5821 std::string msg("Unknown operation node in dag: " +
5822 std::string(operation.name()));
5823
5824 throw InvalidData(__FILE__, __LINE__, __func__, msg);
5825 }
5826
5827 boost::format pattern(operationPat);
5828
5829 int inputs = operation.numberOfInputs();
5830#ifndef NDEBUG
5831 int outputs =
5832#endif
5833 operation.numberOfOutputs();
5834
5835 assert(outputs == 0 || outputs == 1);
5836
5837 for (int i = 1; i < inputs + 1; i++) {
5838 for (int e = 0; e < dag.inDegree(node); e++) {
5839 const OperationDAGEdge& edge = dag.inEdge(node, e);
5840 int dst = edge.dstOperand();
5841 if (dst == i) {
5842 const OperationDAGNode& in = dag.tailNode(edge);
5843 std::string dagNodeString = dagNodeToString(
5844 op, dag, in, emulationPattern, operandTypes,
5845 &operation, &node);
5846 try {
5847 pattern % dagNodeString;
5848 } catch(...) {
5849 TCEString msg = "Boost format threw exception! ";
5850 msg << "Input format: " << operationPat;
5851 throw InvalidData(__FILE__, __LINE__, __func__, msg);
5852 }
5853 }
5854 }
5855 }
5856
5857 return std::string("(") + pattern.str() + ")";
5858}
5859
5860/**
5861 * Returns LLVM .td format string for an operand.
5862 *
5863 * @param operand Operand to return string for.
5864 * @param match True, if the string should be in the matching pattern format.
5865 * @param operandType Character that identifies the type of the operand.
5866 * @return Operand string to be used in a llvm .td pattern.
5867 */
5868// TODO is operandToString correct?
5869std::string
5871 const Operand& operand,
5872 bool match,
5873 char operandType,
5874 const std::string& immDefName) {
5875 int idx = operand.index();
5876
5877 if (operand.isVector() && !operand.isAddress()) {
5878 switch (operandType) {
5879 case OT_VREG_BOOL:
5880 case OT_VREG_INT8:
5881 case OT_VREG_INT16:
5882 case OT_VREG_INT32:
5883 case OT_VREG_FP:
5884 case OT_VREG_HFP: {
5885 TCEString regClass = associatedVectorRegisterClass(operand);
5886 return regClass + ":$op" + Conversion::toString(idx);
5887 }
5888 }
5889 }
5890
5891 // from TDGenSIMD: if (operand.isVector && operand.isAddress()
5892 /// @todo Vector of pointers once supported. Change operand types
5893 /// for GATHER and SCATTER to be mem-data and mem-address, because
5894 /// that will direct the address operand into this if-clause.
5895
5896 if (operand.isAddress()) {
5897 switch (operandType) {
5898 case OT_IMM_INT:
5899 case OT_IMM_LONG:
5900 if (match) {
5901 return "MEMri:$op" + Conversion::toString(idx);
5902 } else {
5903 return "ADDRri:$op" + Conversion::toString(idx);
5904 }
5905 case OT_REG_INT:
5906 case OT_REG_LONG:
5907 if (match) {
5908 return "MEMrr:$op" + Conversion::toString(idx);
5909 } else {
5910 return "ADDRrr:$op" + Conversion::toString(idx);
5911 }
5912 default:
5913 std::string msg =
5914 "invalid operation type for mem operand:";
5915 msg += operandType;
5916 throw InvalidData(__FILE__, __LINE__, __func__, msg);
5917 }
5918 } else if (operand.type() == Operand::SINT_WORD ||
5919 operand.type() == Operand::UINT_WORD ||
5920 operand.type() == Operand::RAW_DATA ||
5921 operand.type() == Operand::BOOL) {
5922
5923 // imm
5924 switch (operandType) {
5925 case OT_IMM_LONG:
5926 if (match) {
5927 return "i64imm:$op" + Conversion::toString(idx);
5928 } else {
5929 return "(i64 imm:$op" + Conversion::toString(idx) + ")";
5930 }
5931 case OT_IMM_INT:
5932 assert(!immDefName.empty() &&
5933 "No immediate operand defined for the operand.");
5934 return immDefName + ":$op" + Conversion::toString(idx);
5935 case OT_IMM_BOOL:
5936 if (match) {
5937 return "i1imm:$op" + Conversion::toString(idx);
5938 } else {
5939 return "(i1 imm:$op" + Conversion::toString(idx) + ")";
5940 }
5941 case OT_REG_INT:
5942 return mach_.is64bit() ?
5943 "R64IRegs:$op" + Conversion::toString(idx):
5944 "R32IRegs:$op" + Conversion::toString(idx);
5945 case OT_REG_LONG:
5946 return "R64IRegs:$op" + Conversion::toString(idx);
5947 case OT_REG_BOOL:
5948 return "R1Regs:$op" + Conversion::toString(idx);
5949 case OT_REG_FP:
5950 if (operand.type() == Operand::RAW_DATA) {
5951 return "FPRegs:$op" + Conversion::toString(idx);
5952 }
5953 /* fall through */
5954 case OT_REG_HFP:
5955 if (operand.type() == Operand::RAW_DATA) {
5956 return "HFPRegs:$op" + Conversion::toString(idx);
5957 }
5958 /* fall through */
5959 default:
5960 std::string msg =
5961 "invalid operation type for integer operand:";
5962 msg += operandType;
5963 throw InvalidData(__FILE__, __LINE__, __func__, msg);
5964 }
5965 } else if (operand.type() == Operand::FLOAT_WORD ) {
5966
5967 switch (operandType) {
5968 case OT_IMM_INT:
5969 case OT_IMM_FP:
5970 if (match) {
5971 return "f32imm:$op" + Conversion::toString(idx);
5972 } else {
5973 return "(f32 fpimm:$op" + Conversion::toString(idx) + ")";
5974 }
5975 case OT_REG_INT:
5976 case OT_REG_FP:
5977 return "FPRegs:$op" + Conversion::toString(idx);
5978
5979 default:
5980 std::string msg =
5981 "invalid operation type for float operand:";
5982 msg += operandType;
5983 throw InvalidData(__FILE__, __LINE__, __func__, msg);
5984 }
5985 } else if (operand.type() == Operand::HALF_FLOAT_WORD) {
5986
5987 switch (operandType) {
5988 case OT_IMM_INT:
5989 case OT_IMM_FP:
5990 case OT_IMM_HFP:
5991 if (match) {
5992 return "f16imm:$op" + Conversion::toString(idx);
5993 } else {
5994 return "(f16 fpimm:$op" + Conversion::toString(idx) + ")";
5995 }
5996 case OT_REG_INT:
5997 case OT_REG_HFP:
5998 return "HFPRegs:$op" + Conversion::toString(idx);
5999 default:
6000 std::string msg =
6001 "invalid operation type for half operand:";
6002 msg += operandType;
6003 throw InvalidData(__FILE__, __LINE__, __func__, msg);
6004 }
6005 } else if (operand.type() == Operand::DOUBLE_WORD) {
6006 // TODO: immediate check??
6007 return "R64DFPRegs:$op" + Conversion::toString(idx);
6008 } else if (operand.type() == Operand::SLONG_WORD ||
6009 operand.type() == Operand::ULONG_WORD) {
6010 if (operandType == OT_REG_BOOL) {
6011 return "R1Regs:$op" + Conversion::toString(idx);
6012 }
6013 if (operandType == OT_IMM_BOOL) {
6014 if (match) {
6015 return "i1imm:$op" + Conversion::toString(idx);
6016 } else {
6017 return "(i1 imm:$op" + Conversion::toString(idx) + ")";
6018 }
6019 }
6020 if (operandType == OT_IMM_LONG) {
6021 return match ?
6022 "i64imm:$op" + Conversion::toString(idx) :
6023 "(i64 imm:$op" + Conversion::toString(idx) + ")";
6024 }
6025 return mach_.is64bit() ?
6026 "R64IRegs:$op" + Conversion::toString(idx):
6027 "R32IRegs:$op" + Conversion::toString(idx);
6028 } else {
6029 std::cerr << "Unknown operand type: " << operandType << std::endl;
6030 assert(false && "Unknown operand type.");
6031 }
6032 abortWithError("Unknown operand type on osal? Should not get here.");
6033 return "";
6034}
6035
6036/**
6037 * Returns llvm input definition list for an operation.
6038 *
6039 * @param op Operation to define inputs for.
6040 * @return String defining operation inputs in llvm .td format.
6041 */
6042std::string
6043TDGen::patInputs(const Operation& op, const std::string& inputTypes) {
6044
6045 std::string ins;
6046 for (int i = 0; i < op.numberOfInputs(); i++) {
6047 if (i > 0) {
6048 ins += ", ";
6049 }
6050
6051 char inputType = inputTypes[i + op.numberOfOutputs()];
6052 std::string immDef("");
6053 // NOTE: !op.operand(i+1).isAddress() is kludge fix for MEMri/ADDri
6054 // operands. They do not have immediate operand definitions (yet).
6055 if (inputType == OT_IMM_INT && !op.operand(i+1).isAddress()) {
6056 assert(immOperandDefs_.count(
6057 ImmInfo::key(op, op.operand(i+1)))
6058 && "Missing immediate operand definition for the operand.");
6059 immDef = immOperandDefs_[ImmInfo::key(op, op.operand(i+1))];
6060 }
6061 ins += operandToString(op.operand(i + 1), true, inputType, immDef);
6062 }
6063 return ins;
6064}
6065
6066
6067/**
6068 * Returns llvm output definition list for an operation.
6069 *
6070 * @param op Operation to define outputs for.
6071 * @return String defining operation outputs in llvm .td format.
6072 */
6073std::string
6074TDGen::patOutputs(const Operation& op, const std::string& operandTypes) {
6075 std::string outs;
6076 for (int i = 0; i < op.numberOfOutputs(); i++) {
6077 assert(op.operand(op.numberOfInputs() + 1 + i).isOutput());
6078 outs += (i > 0) ? (",") : (" ");
6079 outs += operandToString(
6080 op.operand(op.numberOfInputs() + 1 + i), true, operandTypes[i]);
6081 }
6082 return outs;
6083}
6084
6085/**
6086 * Creates a dummy dag for an OSAL operation.
6087 *
6088 * @param op Operation to create OperationDAG for.
6089 * @return OperationDAG consisting of only one operation node referencing
6090 * the given operation.
6091 */
6094
6095 OperationDAG* dag = new OperationDAG(op.impl());
6096 OperationNode* opNode = new OperationNode(op);
6097 dag->addNode(*opNode);
6098
6099 for (int i = 0; i < op.numberOfInputs() + op.numberOfOutputs(); i++) {
6100 const Operand& operand = op.operand(i + 1);
6101 TerminalNode* t = new TerminalNode(operand.index());
6102 dag->addNode(*t);
6103 if (operand.isInput()) {
6104 OperationDAGEdge* e = new OperationDAGEdge(1, operand.index());
6105 dag->connectNodes(*t, *opNode, *e);
6106 } else {
6107 OperationDAGEdge* e = new OperationDAGEdge(operand.index(), 1);
6108 dag->connectNodes(*opNode, *t, *e);
6109 }
6110 }
6111 return dag;
6112}
6113
6114
6115/**
6116 * Returns true if the operand corresponding to the given TerminalNode in
6117 * an OperationDAG can be immediate in the llvm pattern.
6118 *
6119 * @param dag DAG of the whole operation.
6120 * @param node TerminalNode corresponding to the operand queried.
6121 */
6122bool
6124 const OperationDAG& dag, const TerminalNode& node) {
6125
6126 if (dag.inDegree(node) != 0) {
6127 return false;
6128 }
6129
6130 for (int i = 0; i < dag.outDegree(node); i++) {
6131 const OperationDAGEdge& edge = dag.outEdge(node, i);
6132 const OperationDAGNode& dstNode = dag.headNode(edge);
6133 const OperationNode* opNode =
6134 dynamic_cast<const OperationNode*>(&dstNode);
6135
6136 if (opNode == NULL) {
6137 return false;
6138 }
6139 }
6140 return true;
6141}
6142
6143#if 0
6144void
6145TDGen::generateLoadStoreCopyGenerator(std::ostream& os) {
6146 // vector store/load generation code
6147
6148 TCEString prefix = "&"; // address of -operator
6149 TCEString rcpf = "RegsRegClass";
6150 TCEString rapf = "TCE::RARegRegClass";
6151 TCEString boolStore = littleEndian_ ? "ST8Brb;" : "STQBrb;";
6152 TCEString intStore = littleEndian_ ? "ST32" : "STW";
6153 TCEString halfStore = littleEndian_ ? "ST16" : "STH";
6154 TCEString longStore = "ST64";
6155
6156 os << "#include <stdio.h>" << std::endl
6157 << "int GeneratedTCEPlugin::getStore(const TargetRegisterClass *rc)"
6158 << " const {" << std::endl;
6159
6160 os << "\tif (rc == " << prefix << rapf
6161 << ") return TCE::" << intStore << "RArr;"
6162 << std::endl;
6163
6164 for (RegClassMap::iterator ri = regsInClasses_.begin();
6165 ri != regsInClasses_.end(); ri++) {
6166
6167 std::cerr << "Checking reg class: " << ri->first << " for stores." << std::endl;
6168
6169 if (ri->first.find("R1") == 0 ||
6170 ri->first.find(guardRegTemplateName) == 0) {
6171 os << "\tif (rc == " << prefix << "TCE::" << ri->first
6172 << rcpf << ") return TCE::" << boolStore << std::endl;
6173 }
6174 if (ri->first.find("R32") == 0) {
6175 os << "\tif (rc == " << prefix << "TCE::" << ri->first
6176 << rcpf << ") return TCE::" << intStore << "rr;" << std::endl;
6177
6178 os << "\tif (rc == " << prefix << "TCE::" << ri->first
6179 << "I" << rcpf << ") return TCE::" << intStore << "rr;" << std::endl;
6180
6181 os << "\tif (rc == " << prefix << "TCE::" << ri->first
6182 << "FP" << rcpf << ") return TCE::" << intStore << "fr;" << std::endl;
6183
6184 os << "\tif (rc == " << prefix << "TCE::" << ri->first
6185 << "HFP" << rcpf << ") return TCE::" << halfStore << "hr;" << std::endl;
6186 }
6187 if (mach_.is64bit()) {
6188 if (ri->first.find("R64") == 0) {
6189 os << "\tif (rc == " << prefix << "TCE::" << ri->first
6190 << rcpf << ") return TCE::" << longStore << "ss;" << std::endl;
6191 }
6192
6193 if (ri->first.find("R64") == 0) {
6194 os << "\tif (rc == " << prefix << "TCE::" << ri->first
6195 << "I" << rcpf << ") return TCE::" << longStore << "ss;" << std::endl;
6196 }
6197
6198 if (ri->first.find("R64") == 0) {
6199 os << "\tif (rc == &TCE::" << ri->first << "FP" << rcpf
6200 << ") return TCE::" << longStore << "fs;" << std::endl;
6201 }
6202
6203 if (ri->first.find("R64") == 0) {
6204 os << "\tif (rc == &TCE::" << ri->first << "HFP" << rcpf
6205 << ") return TCE::" << longStore << "hs;" << std::endl;
6206 }
6207
6208 if (ri->first.find("R64") == 0) {
6209 os << "\tif (rc == &TCE::" << ri->first << "DFP" << rcpf
6210 << ") return TCE::" << longStore << "ds;" << std::endl;
6211 }
6212
6213 }
6214 }
6215
6216 if (use64bitForFP_) {
6217 os << "\tif (rc == &TCE::FPRegsRegClass) return TCE::ST64fs;"
6218 << std::endl;
6219
6220 os << "\tif (rc == &TCE::HFPRegsRegClass) return TCE::ST64hs;"
6221 << std::endl;
6222 } else {
6223 os << "\tif (rc == &TCE::FPRegsRegClass) return TCE::"
6224 << intStore << "fr;" << std::endl;
6225
6226 os << "\tif (rc == &TCE::HFPRegsRegClass) return TCE::"
6227 << intStore << "hr;" << std::endl;
6228 }
6229
6230 for (RegClassMap::iterator ri = regsInRFClasses_.begin();
6231 ri != regsInRFClasses_.end(); ri++) {
6232 os << "\tif (rc == "
6233 << prefix << "TCE::R32_" << ri->first << "_"
6234 << rcpf << ") return TCE::" <<intStore << "rr;" << std::endl;
6235 }
6236
6237 TCEString boolLoad = littleEndian_ ? "LD8" : "LDQ";
6238 if (!mach_.hasOperation(boolLoad)) {
6239 boolLoad = littleEndian_ ? "LDU8" : "LDQU";
6240 if (!mach_.hasOperation(boolLoad)) {
6241 boolLoad="";
6242 }
6243 }
6244
6245 TCEString intLoad = littleEndian_ ? "LD32" : "LDW";
6246 TCEString halfLoad = littleEndian_ ? "LD16" : "LDH";
6247 TCEString longLoad = "LD64";
6248 if (!mach_.hasOperation(halfLoad)) {
6249 halfLoad = littleEndian_ ? "LDU16;" : "LDHU";
6250 if (!mach_.hasOperation(halfLoad)) {
6251 halfLoad="";
6252 }
6253 }
6254
6255 os << "\tprintf(\"regclass of size %d \\n\",rc->MC->RegsSize);"
6256 << std::endl
6257 << "\tassert(0&&\"Storing given regclass to stack not supported. "
6258 << "Bug in backend?\");"
6259 << std::endl
6260 << "} " << std::endl
6261 << std::endl
6262
6263 << "int GeneratedTCEPlugin::getLoad(const TargetRegisterClass *rc)"
6264 << " const {" << std::endl;
6265
6266 os << "\tif (rc == " << prefix << rapf << ") return TCE::" << intLoad << "RAr;"
6267 << std::endl;
6268
6269 if (!mach_.hasOperation(intLoad) && mach_.hasOperation("LDU32")) {
6270 intLoad = "LDU32";
6271 }
6272
6273 for (RegClassMap::iterator ri = regsInClasses_.begin();
6274 ri != regsInClasses_.end(); ri++) {
6275 std::cerr << "Checking reg class: " << ri->first << " for loads." << std::endl;
6276 if (ri->first.find("R1") == 0) {
6277 if (boolLoad != "") {
6278 os << "\tif (rc == " << prefix << "TCE::" << ri->first
6279 << rcpf <<") return TCE::" << boolLoad << "Br;" << std::endl;
6280 } else {
6281 os << "\tif (rc == " << prefix << "TCE::" << ri->first
6282 << rcpf <<") return TCE::" << intLoad << "Br;" << std::endl;
6283 }
6284 }
6285 if (ri->first.find("R32") == 0) {
6286 os << "\tif (rc == " << prefix << "TCE::" << ri->first
6287 << rcpf << ") return TCE::" << intLoad << "rr;" << std::endl;
6288
6289 os << "\tif (rc == " << prefix << "TCE::" << ri->first
6290 << "I" << rcpf << ") return TCE::" << intLoad << "rr;" << std::endl;
6291
6292 os << "\tif (rc == " << prefix << "TCE::" << ri->first
6293 << "FP" << rcpf << ") return TCE::" << intLoad << "fr;" << std::endl;
6294
6295 if (halfLoad != "") {
6296 os << "\tif (rc == " << prefix << "TCE::" << ri->first
6297 << "HFP" << rcpf << ") return TCE::" << halfLoad << "hr;" << std::endl;
6298 }
6299 }
6300
6301 if (mach_.is64bit()) {
6302 if (ri->first.find("R64") == 0) {
6303 os << "\tif (rc == " << prefix << "TCE::" << ri->first
6304 << rcpf << ") return TCE::" << longLoad << "ss;" << std::endl;
6305
6306 os << "\tif (rc == " << prefix << "TCE::" << ri->first
6307 << "I" << rcpf << ") return TCE::" << longLoad << "ss;" << std::endl;
6308
6309 os << "\tif (rc == &TCE::" << ri->first << "FP" << rcpf
6310 << ") return TCE::" << longLoad << "fs;" << std::endl;
6311
6312 os << "\tif (rc == &TCE::" << ri->first << "HFP" << rcpf
6313 << ") return TCE::" << longLoad << "hs;" << std::endl;
6314
6315 os << "\tif (rc == &TCE::" << ri->first << "DFP" << rcpf
6316 << ") return TCE::" << longLoad << "ds;" << std::endl;
6317 }
6318 }
6319 // TODO: double load!
6320
6321 }
6322
6323 // TODO: what is this?
6324 for (RegClassMap::iterator ri = regsInRFClasses_.begin();
6325 ri != regsInRFClasses_.end(); ri++) {
6326
6327 os << "\tif (rc == " << prefix
6328 << "TCE::R32_" << ri->first << "_"
6329 << rcpf << ") return TCE::" << intLoad << "rr;" << std::endl;
6330
6331 }
6332
6333 if (use64bitForFP_) {
6334 os << "\tif (rc == &TCE::FPRegsRegClass) return TCE::LD64fs;"
6335 << std::endl;
6336
6337 os << "\tif (rc == &TCE::HFPRegsRegClass) return TCE::LD64hs;"
6338 << std::endl;
6339 } else {
6340 os << "\tif (rc == &TCE::FPRegsRegClass) return TCE::" << intLoad << "fr;"
6341 << std::endl;
6342
6343 os << "\tif (rc == &TCE::HFPRegsRegClass) return TCE::" << intLoad << "hr;"
6344 << std::endl;
6345 }
6346
6347 os << "\tprintf(\"regclass of size %d \\n\",rc->MC->RegsSize);"
6348 << std::endl
6349 << "\tassert(0&&\"loading from stack to given regclass not supported."
6350 << " Bug in backend?\");"
6351 << std::endl
6352 << "} " << std::endl
6353 << std::endl;
6354 }
6355}
6356
6357#endif
6358
6359/**
6360 * Generates implementations of getLoad() and getStore() to Backend.inc file.
6361 *
6362 * @param os Output stream to the file.
6363 */
6364void
6369
6371 const TCEString& opName, const TCEString& valueName, std::ostream& os) {
6372 if (opNames_.find(opName) != opNames_.end()) {
6373 os << "\tif (vt == MVT::" << valueName << ") return TCE::"
6374 << opName << ";" << std::endl;
6375 }
6376}
6377
6378
6379void
6381 const TCEString& baseOpName,
6382 int bits,
6383 char llvmTypeChar,
6384 const TCEString& postFix,
6385 std::ostream& os) {
6386
6387 for (int elemCount=2; elemCount <= 1024; elemCount<<=1) {
6388 TCEString opName = baseOpName;
6389 opName << bits << "X" << elemCount << postFix;
6390 TCEString vecType = "v";
6391 vecType << elemCount << (TCEString)(llvmTypeChar) << bits;
6392 createMinMaxDef(opName, vecType, os);
6393 }
6394}
6395
6396
6397void
6399
6400 bool is64bit = mach_.is64bit();
6401 // MIN
6402 os << "int GeneratedTCEPlugin::getMinOpcode(SDNode* n) const {" << std::endl
6403 << "\tEVT vt = n->getOperand(1).getValueType();" << std::endl;
6404 if (!is64bit) {
6405 if (opNames_.find("MINrrr") != opNames_.end()) {
6406 os << "if (vt == MVT::i32) return TCE::MINrrr;" << std::endl;
6407 }
6408 } else {
6409 if (opNames_.find("MIN64sss") != opNames_.end()) {
6410 os << "if (vt == MVT::i64) return TCE::MIN64sss;" << std::endl;
6411 }
6412 }
6413 if (opNames_.find("MINFfff") != opNames_.end()) {
6414 os << "if (vt == MVT::f32) return TCE::MINFfff;" << std::endl;
6415 }
6416
6417 createVectorMinMaxDef("MINH", 16, 'f', "ggg", os);
6418 createVectorMinMaxDef("MINF", 32, 'f', "eee", os);
6419 createVectorMinMaxDef("MIN", 32, 'i', "uuu", os);
6420 createVectorMinMaxDef("MIN", 16, 'i', "ttt", os);
6421
6422 os << "\treturn -1; " << std::endl << "}" << std::endl;
6423
6424 // MAX
6425 os << "int GeneratedTCEPlugin::getMaxOpcode(SDNode* n) const {" << std::endl
6426 << "\tEVT vt = n->getOperand(1).getValueType();" << std::endl;
6427
6428 if (!is64bit) {
6429 if (opNames_.find("MAXrrr") != opNames_.end()) {
6430 os << "if (vt == MVT::i32) return TCE::MAXrrr;" << std::endl;
6431 }
6432 } else {
6433 if (opNames_.find("MAX64sss") != opNames_.end()) {
6434 os << "if (vt == MVT::i64) return TCE::MAX64sss;" << std::endl;
6435 }
6436
6437 }
6438 if (opNames_.find("MAXFfff") != opNames_.end()) {
6439 os << "if (vt == MVT::f32) return TCE::MAXFfff;" << std::endl;
6440 }
6441
6442 createVectorMinMaxDef("MAXH", 16, 'f', "ggg", os);
6443 createVectorMinMaxDef("MAXF", 32, 'f', "eee", os);
6444 createVectorMinMaxDef("MAX", 32, 'i', "uuu", os);
6445 createVectorMinMaxDef("MAX", 16, 'i', "ttt", os);
6446
6447 os << "\treturn -1; " << std::endl << "}" << std::endl;
6448
6449 // MINU
6450 os << "int GeneratedTCEPlugin::getMinuOpcode(SDNode* n) const {" << std::endl;
6451 os << "\tEVT vt = n->getOperand(1).getValueType();" << std::endl;
6452
6453 if (!is64bit) {
6454 if (opNames_.find("MINUrrr") != opNames_.end()) {
6455 os << "if (vt == MVT::i32) return TCE::MINUrrr;" << std::endl;
6456 }
6457 } else {
6458 if (opNames_.find("MINU64sss") != opNames_.end()) {
6459 os << "if (vt == MVT::i64) return TCE::MINU64sss;" << std::endl;
6460 }
6461 }
6462 createVectorMinMaxDef("MINU", 32, 'i', "uuu", os);
6463 createVectorMinMaxDef("MINU", 16, 'i', "ttt", os);
6464
6465 os << "\treturn -1; " << std::endl << "}" << std::endl;
6466
6467 // MAXU
6468 os << "int GeneratedTCEPlugin::getMaxuOpcode(SDNode* n) const {" << std::endl;
6469 os << "\tEVT vt = n->getOperand(1).getValueType();" << std::endl;
6470
6471
6472 if (!is64bit) {
6473 if (opNames_.find("MAXUrrr") != opNames_.end()) {
6474 os << "if (vt == MVT::i32) return TCE::MAXUrrr;" << std::endl;
6475 }
6476 } else {
6477 if (opNames_.find("MAXU64sss") != opNames_.end()) {
6478 os << "if (vt == MVT::i64) return TCE::MAXU64sss;" << std::endl;
6479 }
6480 }
6481
6482 createVectorMinMaxDef("MAXU", 32, 'i', "uuu", os);
6483 createVectorMinMaxDef("MAXU", 16, 'i', "ttt", os);
6484 os << "\treturn -1; " << std::endl << "}" << std::endl;
6485}
6486
6487void TDGen::createEndiannesQuery(std::ostream& os) {
6488 bool is64bit = mach_.is64bit();
6489 os << "bool GeneratedTCEPlugin::isLittleEndian() const {" << std::endl;
6490 os << "return " << littleEndian_ << "; }" << std::endl;
6491 os << "bool GeneratedTCEPlugin::is64bit() const {" << std::endl;
6492 os << "return " << is64bit << "; }" << std::endl;
6493}
6494
6495/**
6496 * Creates query function for TCEISelLowering for testing if otherwise
6497 * unsupported constant as immediate can be materialized instead of converting
6498 * it to constant pool load.
6499 */
6500void
6502
6504 os << "bool GeneratedTCEPlugin::canMaterializeConstant("
6505 << "const ConstantInt&) const { " << std::endl
6506 << " return false;" << std::endl
6507 << "};" << std::endl;
6508 return;
6509 }
6510
6511 os << "bool GeneratedTCEPlugin::canMaterializeConstant("
6512 << "const ConstantInt& ci) const {"
6513 << std::endl
6514 << " int64_t Imm = ci.getSExtValue();" << std::endl
6515 << " if (";
6516 bool first = true;
6517 for (auto& predicate : constantMaterializationPredicates_) {
6518 if (!first) {
6519 os << std::endl << " || ";
6520 }
6521 os << "(" << predicate << ")";
6522 first = false;
6523 }
6524 os << ") {"
6525 << " return true;" << std::endl
6526 << " }" << std::endl
6527 << " return false;" << std::endl
6528 << "}" << std::endl;
6529}
6530
6531void TDGen::createByteExtLoadPatterns(std::ostream& os) {
6532 TCEString load = littleEndian_ ? "LD8" : "LDQ";
6533 TCEString uload = littleEndian_ ? "LDU8" : "LDQU";
6534 TCEString destSize = mach_.is64bit() ? "64" : "32";
6535 int bits = mach_.is64bit() ? 64 : 32;
6536 TCEString ANDIMM = mach_.is64bit() ? "AND64ssa" : "ANDrri";
6537 TCEString ANDREG = mach_.is64bit() ? "AND64sss" : "ANDrrr";
6538 TCEString SUBIMM = mach_.is64bit() ? "SUB64sas" : "SUBrir";
6539 TCEString EXTOP = mach_.is64bit() ? "SXQ64" : "SXQW";
6540 TCEString EXTOPC = mach_.is64bit() ? "SXQ64sr" : "SXQWrr";
6541 TCEString SHL = mach_.is64bit() ? "SHL" : "SHL64";
6542 TCEString SHR = mach_.is64bit() ? "SHR" : "SHR64";
6543 TCEString SHRU = mach_.is64bit() ? "SHRU" : "SHRU64ssa";
6544 TCEString SHLOPC = mach_.is64bit() ? "SHLrri" : "SHL64ssa";
6545 TCEString SHROPC = mach_.is64bit() ? "SHRrri" : "SHR64ssa";
6546 TCEString SHRUOPC = mach_.is64bit() ? "SHRUrri" : "SHRU64ssa";
6547 TCEString SHL4 = mach_.is64bit() ? "SHL4_32" : "SHL4_64";
6548 TCEString SHR4 = mach_.is64bit() ? "SHR4_32" : "SHR4_64";
6549 TCEString SHRU4 = mach_.is64bit() ? "SHRU4_32" : "SHRU4_64ssa";
6550 TCEString regSrcChar = mach_.is64bit() ? OT_REG_LONG : OT_REG_INT;
6551 TCEString dstTypeChar = OT_REG_INT;
6552 TCEString immSrcChar = mach_.is64bit() ? OT_IMM_LONG : OT_IMM_INT;
6553 TCEString loadOpcReg = load + dstTypeChar + regSrcChar;
6554 TCEString loadOpcImm = load + dstTypeChar + immSrcChar;
6555
6556 if (mach_.hasOperation(load)) {
6557 if (!mach_.hasOperation(uload)) {
6558
6559 // emulate zero ext with sing-ext and and
6560 os << "def : Pat<(i" << destSize << " (zextloadi8 ADDRrr:$addr)), "
6561 << "(" << ANDIMM << " ("
6562 << loadOpcReg << " ADDRrr:$addr), 255)>;"
6563 << std::endl;
6564 os << "def : Pat<(i" << destSize << " (zextloadi8 ADDRri:$addr)), "
6565 << "(" << ANDIMM << " ("
6566 << loadOpcImm << " ADDRri:$addr), 255)>;"
6567 << std::endl;
6568 }
6569 } else {
6570 // if no sign ext load, try zero ext load
6571 if (!mach_.hasOperation(uload)) {
6572 std::cerr << "Warning: The architecture is missing any 8-bit loads."
6573 << " All code may not compile!"
6574 << std::endl;
6575 return;
6576 }
6577 loadOpcReg = uload + dstTypeChar + regSrcChar;
6578 loadOpcImm = uload + dstTypeChar + immSrcChar;
6579
6580 if (mach_.hasOperation(EXTOP)) {
6581 // use zextload + sext for sextload
6582 os << "def : Pat<(i" << destSize
6583 << " (sextloadi8 ADDRrr:$addr)), "
6584 << "(" << EXTOPC << " ("
6585 << loadOpcReg << " ADDRrr:$addr))>;" << std::endl;
6586 os << "def : Pat<(i" << destSize
6587 << " (sextloadi8 ADDRri:$addr)), "
6588 << "(" << EXTOPC << " ("
6589 << loadOpcImm << " ADDRri:$addr))>;" << std::endl;
6590
6591 } else {
6592 if (mach_.hasOperation(SHL) && mach_.hasOperation(SHR)) {
6593
6594 int sb = bits -8;
6595 os << "def : Pat<(i" << destSize
6596 << " (sextloadi16 ADDRrr:$addr)), "
6597 << "(" << SHROPC << " (" << SHLOPC << " ("
6598 << load << "rr ADDRrr:$addr), "
6599 << sb << "), " << sb << ")>;" << std::endl;
6600
6601 os << "def : Pat<(i" << destSize
6602 << " (sextloadi16 ADDRri:$addr)), "
6603 << "(" << SHROPC << " (" << SHLOPC << " ("
6604 << load << "ri ADDRri:$addr), "
6605 << sb << "), " << sb << ")>;" << std::endl;
6606 } else if (mach_.hasOperation(SHL4) &&
6607 mach_.hasOperation(SHR4)) {
6608 if (!mach_.is64bit()) {
6609 os << "def : Pat<(i32 (sextloadi8 ADDRrr:$addr)), "
6610 << "(SHR4_32rr (SHR4_32rr (SHR4_32rr (SHR4_32rr "
6611 << "(SHR4_32rr (SHR4_32rr "
6612 << "(SHL4_32rr (SHL4_32rr (SHL4_32rr (SHL4_32rr "
6613 << "(SHL4_32rr (SHL4_32rr ("
6614 << load << "rr ADDRrr:$addr)))))))))))))>;"
6615 << std::endl;
6616
6617 os << "def : Pat<(i32 (sextloadi8 ADDRri:$addr)), "
6618 << "(SHR4_32rr (SHR4_32rr (SHR4_32rr (SHR4_32rr "
6619 << "(SHR4_32rr (SHR4_32rr "
6620 << "(SHL4_32rr (SHL4_32rr (SHL4_32rr (SHL4_32rr "
6621 << "(SHL4_32rr (SHL4_32rr ("
6622 << load << "ri ADDRri:$addr)))))))))))))>;"
6623 << std::endl;
6624 } else {
6625 os << "def : Pat<(i64 (sextloadi8 ADDRrr:$addr)), "
6626 << "(SHR4_64ss (SHR4_64ss (SHR4_64ss (SHR4_64ss "
6627 << "(SHR4_64ss (SHR4_64ss (SHR4_64ss (SHR4_64ss "
6628 << "(SHR4_64ss (SHR4_64ss (SHR4_64ss (SHR4_64ss "
6629 << "(SHR4_64ss (SHR4_64ss "
6630 << "(SHL4_64ss (SHL4_64ss (SHL4_64ss (SHL4_64ss "
6631 << "(SHL4_64ss (SHL4_64ss (SHL4_64ss (SHL4_64ss "
6632 << "(SHL4_64ss (SHL4_64ss (SHL4_64ss (SHL4_64ss "
6633 << "(SHL4_64ss (SHL4_64ss ("
6634 << load << "rr ADDRrr:$addr)))))))))))))>;"
6635 << std::endl;
6636
6637 os << "def : Pat<(i64 (sextloadi8 ADDRri:$addr)), "
6638 << "(SHR4_64ss (SHR4_64ss (SHR4_64ss (SHR4_64ss "
6639 << "(SHR4_64ss (SHR4_64ss (SHR4_64ss (SHR4_64ss "
6640 << "(SHR4_64ss (SHR4_64ss (SHR4_64ss (SHR4_64ss "
6641 << "(SHR4_64ss (SHR4_64ss "
6642 << "(SHL4_64ss (SHL4_64ss (SHL4_64ss (SHL4_64ss "
6643 << "(SHL4_64ss (SHL4_64ss (SHL4_64ss (SHL4_64ss "
6644 << "(SHL4_64ss (SHL4_64ss (SHL4_64ss (SHL4_64ss "
6645 << "(SHL4_64ss (SHL4_64ss ("
6646 << load << "ri ADDRri:$addr)))))))))))))>;"
6647 << std::endl;
6648 }
6649 } else {
6650 std::cerr << "Warning: no sign-extending 8-bit loads,"
6651 << " 8-bit sign extension instruction or suitable"
6652 << " shifts for sext-emulation in the processor."
6653 << " All code may not compile!" << std::endl;
6654 }
6655 }
6656 }
6657
6658 // TODO: is there a more capable version of this code
6659 // commented out above???
6660
6661 os << "def : Pat<(i" << destSize << " (zextloadi1 ADDRrr:$addr)), ("
6662 << loadOpcReg << " ADDRrr:$addr)>;"
6663 << std::endl
6664 << "def : Pat<(i" << destSize << " (zextloadi1 ADDRri:$addr)), ("
6665 << loadOpcImm << " ADDRri:$addr)>;"
6666 << std::endl;
6667
6668 os << "def : Pat<(i" << destSize << " (sextloadi1 ADDRrr:$addr)), "
6669 << "(" << SUBIMM << " 0, "
6670 << "(" << ANDREG << " ("
6671 << loadOpcReg << " ADDRrr:$addr), 1))>;"
6672 << std::endl
6673 << "def : Pat<(i" << destSize << " (sextloadi1 ADDRri:$addr)), "
6674 << "(" << SUBIMM << " 0, "
6675 << "(" << ANDREG << " ("
6676 << loadOpcImm << " ADDRri:$addr), 1))>;"
6677 << std::endl
6678 << "// anyextloads" << std::endl;
6679
6680 os << "def : Pat<(i" << destSize << " (extloadi1 ADDRrr:$src)), ("
6681 << loadOpcReg << " ADDRrr:$src)>;" << std::endl
6682 << "def : Pat<(i" << destSize << " (extloadi1 ADDRri:$src)), ("
6683 << loadOpcImm << " ADDRri:$src)>;" << std::endl
6684 << "def : Pat<(i" << destSize << " (extloadi8 ADDRrr:$src)), ("
6685 << loadOpcReg << " ADDRrr:$src)>;" << std::endl
6686 << "def : Pat<(i" << destSize << " (extloadi8 ADDRri:$src)), ("
6687 << loadOpcImm << " ADDRri:$src)>;" << std::endl
6688 << std::endl;
6689}
6690
6692 TCEString load = littleEndian_ ? "LD16" : "LDH";
6693 TCEString destSize = mach_.is64bit() ? "64" : "32";
6694 int bits = mach_.is64bit() ? 64 : 32;
6695 TCEString ANDOPC = mach_.is64bit() ? "AND64ssa" : "ANDrri";
6696 TCEString uload = littleEndian_ ? "LDU16" : "LDHU";
6697 TCEString EXTOP = mach_.is64bit() ? "SXH64" : "SXHW";
6698 TCEString EXTOPC = mach_.is64bit() ? "SXH64sr" : "SXHWrr";
6699 TCEString regSrcChar = mach_.is64bit() ? OT_REG_LONG : OT_REG_INT;
6700 TCEString dstTypeChar = OT_REG_INT;
6701 TCEString immSrcChar = mach_.is64bit() ? OT_IMM_LONG : OT_IMM_INT;
6702 TCEString loadOpcReg = load + dstTypeChar + regSrcChar;
6703 TCEString loadOpcImm = load + dstTypeChar + immSrcChar;
6704
6705 TCEString SHL = mach_.is64bit() ? "SHL" : "SHL64";
6706 TCEString SHR = mach_.is64bit() ? "SHR" : "SHR64";
6707 TCEString SHRU = mach_.is64bit() ? "SHRU" : "SHRU64ssa";
6708 TCEString SHLOPC = mach_.is64bit() ? "SHLrri" : "SHL64ssa";
6709 TCEString SHROPC = mach_.is64bit() ? "SHRrri" : "SHR64ssa";
6710 TCEString SHRUOPC = mach_.is64bit() ? "SHRUrri" : "SHRU64ssa";
6711 TCEString SHL4 = mach_.is64bit() ? "SHL4_32" : "SHL4_64";
6712 TCEString SHR4 = mach_.is64bit() ? "SHR4_32" : "SHR4_64";
6713 TCEString SHRU4 = mach_.is64bit() ? "SHRU4_32" : "SHRU4_64ssa";
6714
6715 if (mach_.hasOperation(load)) {
6716 if (!mach_.hasOperation(uload)) {
6717 // emulate zero ext with sing-ext and and
6718 os << "def : Pat<(i" << destSize
6719 << " (zextloadi16 ADDRrr:$addr)), "
6720 << "(" << ANDOPC << " (" << loadOpcReg
6721 << " ADDRrr:$addr), 65535)>;" << std::endl;
6722 os << "def : Pat<(i" << destSize
6723 << " (zextloadi16 ADDRri:$addr)), "
6724 << "(" << ANDOPC << " ("
6725 << loadOpcImm << " ADDRri:$addr), 65535)>;" << std::endl;
6726 }
6727 } else {
6728 if (!mach_.hasOperation(uload)) {
6729 std::cerr << "Warning: The architecture is missing any 16-bit loads."
6730 << std::endl;
6731 return;
6732 }
6733 loadOpcReg = uload + dstTypeChar + regSrcChar;
6734 loadOpcImm = uload + dstTypeChar + immSrcChar;
6735
6736 if (mach_.hasOperation(EXTOP)) {
6737 // use zextload + sext for sextload
6738 os << "def : Pat<(i" << destSize
6739 << " (sextloadi16 ADDRrr:$addr)), "
6740 << "(" << EXTOPC
6741 << " (" << loadOpcReg << " ADDRrr:$addr))>;" << std::endl;
6742 os << "def : Pat<(i" << destSize
6743 << " (sextloadi16 ADDRri:$addr)), "
6744 << "(" << EXTOPC
6745 << " (" << loadOpcImm << " ADDRri:$addr))>;" << std::endl;
6746 } else {
6747 if (mach_.hasOperation(SHL) && mach_.hasOperation(SHR)) {
6748 int sb = bits -16;
6749 os << "def : Pat<(i" << destSize
6750 << " (sextloadi16 ADDRrr:$addr)), "
6751 << "(" << SHROPC << " (" << SHLOPC << " ("
6752 << load << "rr ADDRrr:$addr), "
6753 << sb << "), " << sb << ")>;" << std::endl;
6754
6755 os << "def : Pat<(i" << destSize
6756 << " (sextloadi16 ADDRri:$addr)), "
6757 << "(" << SHROPC << " (" << SHLOPC << " ("
6758 << load << "ri ADDRri:$addr), "
6759 << sb << "), " << sb << ")>;" << std::endl;
6760 } else if (mach_.hasOperation(SHL4) &&
6761 mach_.hasOperation(SHR4)) {
6762 if (!mach_.is64bit()) {
6763 os << "def : Pat<(i32 (sextloadi16 ADDRrr:$addr)), "
6764 << "(SHR4_32rr (SHR4_32rr (SHR4_32rr (SHR4_32rr "
6765 << "(SHL4_32rr (SHL4_32rr (SHL4_32rr (SHL4_32rr ("
6766 << load << "rr ADDRrr:$addr)))))))))>;" << std::endl;
6767
6768 os << "def : Pat<(i32 (sextloadi16 ADDRri:$addr)), "
6769 << "(SHR4_32rr (SHR4_32rr (SHR4_32rr (SHR4_32rr "
6770 << "(SHL4_32rr (SHL4_32rr (SHL4_32rr (SHL4_32rr ("
6771 << load << "ri ADDRri:$addr)))))))))>;" << std::endl;
6772 } else {
6773 os << "def : Pat<(i64 (sextloadi8 ADDRrr:$addr)), "
6774 << "(SHR4_64ss (SHR4_64ss (SHR4_64ss (SHR4_64ss "
6775 << "(SHR4_64ss (SHR4_64ss (SHR4_64ss (SHR4_64ss "
6776 << "(SHR4_64ss (SHR4_64ss (SHR4_64ss (SHR4_64ss "
6777 << "(SHL4_64ss (SHL4_64ss (SHL4_64ss (SHL4_64ss "
6778 << "(SHL4_64ss (SHL4_64ss (SHL4_64ss (SHL4_64ss "
6779 << "(SHL4_64ss (SHL4_64ss (SHL4_64ss (SHL4_64ss ("
6780 << load << "rr ADDRrr:$addr)))))))))))))>;"
6781 << std::endl;
6782
6783 os << "def : Pat<(i64 (sextloadi8 ADDRri:$addr)), "
6784 << "(SHR4_64ss (SHR4_64ss (SHR4_64ss (SHR4_64ss "
6785 << "(SHR4_64ss (SHR4_64ss (SHR4_64ss (SHR4_64ss "
6786 << "(SHR4_64ss (SHR4_64ss (SHR4_64ss (SHR4_64ss "
6787 << "(SHL4_64ss (SHL4_64ss (SHL4_64ss (SHL4_64ss "
6788 << "(SHL4_64ss (SHL4_64ss (SHL4_64ss (SHL4_64ss "
6789 << "(SHL4_64ss (SHL4_64ss (SHL4_64ss (SHL4_64ss ("
6790 << load << "ri ADDRri:$addr)))))))))))))>;"
6791 << std::endl;
6792 }
6793 } else {
6794 std::cerr << "Warning: no sign-extending 16-bit loads,"
6795 << " 16-bit sign extension instruction or suitable"
6796 << " shifts for sext-emulation in the processor."
6797 << " All code may not compile!" << std::endl;
6798 }
6799 }
6800 }
6801 // anyext
6802 os << "def : Pat<(i" << destSize << " (extloadi16 ADDRrr:$src)), ("
6803 << loadOpcReg << " ADDRrr:$src)>;" << std::endl
6804 << "def : Pat<(i" << destSize << " (extloadi16 ADDRri:$src)), ("
6805 << loadOpcImm << " ADDRri:$src)>;" << std::endl;
6806}
6807
6809 TCEString load = "LD32";
6810 const TCEString uload = "LDU32";
6811 TCEString ZXOP = "ZXW64";
6812 TCEString ZXOPC = "ZXW64ss";
6813
6814 if (mach_.hasOperation(load)) {
6815 if (!mach_.hasOperation(uload)) {
6816 if (!mach_.hasOperation(ZXOP)) {
6817 // emulate zero ext with sing-ext and and
6818 os << "def : Pat<(i64 (zextloadi32 ADDRrr:$addr)), "
6819 << "(AND64ssa (LD32ss ADDRrr:$addr),"
6820 << "0xffffffff)>;" << std::endl;
6821
6822 os << "def : Pat<(i64 (zextloadi32 ADDRri:$addr)), "
6823 << "(AND64ssa (LD32sa ADDRri:$addr),"
6824 << "0xffffffff)>;" << std::endl;
6825 } else {
6826 // use zxw64 instr for zext
6827 os << "def : Pat<(i64 (zextloadi32 ADDRrr:$addr)), "
6828 << "(" << ZXOPC << " (LD32ss ADDRrr:$addr))>;" <<std::endl;
6829
6830 os << "def : Pat<(i64 (zextloadi32 ADDRri:$addr)), "
6831 << "(" << ZXOPC << " (LD32sa ADDRri:$addr))>;" <<std::endl;
6832 }
6833 }
6834 } else {
6835 if (!mach_.hasOperation(uload)) {
6836 std::cerr << "Warning: The architecture is missing any 16-bit loads."
6837 << std::endl;
6838 return;
6839 }
6840 load = uload;
6841
6842 if (mach_.hasOperation("SXW64")) {
6843 // use zextload + sext for sextload
6844 os << "def : Pat<(i64 (sextloadi32 ADDRrr:$addr)), "
6845 << "(SXW64ss (LDU32ss ADDRrr:$addr))>;" << std::endl;
6846
6847 os << "def : Pat<(i64 (sextloadi32 ADDRri:$addr)), "
6848 << "(SXW64ss (LDU32sa ADDRri:$addr))>;" << std::endl;
6849 } else {
6850 std::cerr << "Warning: no sign-extending 32-bit loads or"
6851 << " 32-bit sign extension instruction!"
6852 << " in the processor. All code may not compile!"
6853 << std::endl;
6854 }
6855 }
6856 // anyext.
6857 os << "def : Pat<(i64 (extloadi32 ADDRrr:$src)), "
6858 << "(" << load << "ss ADDRrr:$src)>;" << std::endl
6859
6860 << "def : Pat<(i64 (extloadi32 ADDRri:$src)), "
6861 << "(" << load << "sa ADDRrr:$src)>;" << std::endl;
6862}
6863
6864/**
6865 * Writes details about function arguments and returns values.
6866 *
6867 * @param o Output stream to the file.
6868 */
6869void
6870TDGen::writeCallingConv(std::ostream& os) {
6872
6873 int bits = mach_.is64bit() ? 64 : 32;
6874 int bytes = mach_.is64bit() ? 8 : 4;
6875 // Function return value types.
6876 os << "// Function return value types." << endl;
6877 os << "def RetCC_TCE : CallingConv<[" << endl;
6878 if (mach_.is64bit()) {
6879 os << " CCIfType<[i1], CCPromoteToType<i64>>," << endl
6880 << " CCIfType<[i32], CCPromoteToType<i64>>," << endl
6881 << " CCIfType<[i64], CCAssignToReg<[IRES0]>>," << endl
6882 << " CCIfType<[f64], CCAssignToReg<[IRES0]>>," << endl << endl;
6883 } else {
6884 os << " CCIfType<[i1], CCPromoteToType<i32>>," << endl;
6885 os << " CCIfType<[i32], CCAssignToReg<[IRES0]>>," << endl;
6886 }
6887
6888 os << " CCIfType<[f16], CCAssignToReg<[IRES0]>>," << endl
6889 << " CCIfType<[f32], CCAssignToReg<[IRES0]>>," << endl << endl;
6890
6891 os << " // Vector value types." << endl;
6892 std::map<TCEString, RegisterClass>::const_iterator rcIt;
6893 for (rcIt = vRegClasses_.begin(); rcIt != vRegClasses_.end(); ++rcIt) {
6894 const TCEString& vtStr = rcIt->first;
6895 const RegisterClass& regClass = rcIt->second;
6896
6897 if (regClass.numberOfRegisters() > 0) {
6898 os << " CCIfType<[" << vtStr << "], CCAssignToReg<[";
6899 if (regClass.valueType().width() <= bits) {
6900 os << "IRES0";
6901 } else {
6902 os << regClass.registerInfo(0).regName_;
6903 }
6904 os << "]>>," << endl;
6905 } else {
6906 verbose("ValueType " + vtStr + " can not be a return value");
6907 }
6908 }
6909
6910 os << " CCAssignToStack<" << bytes << ", " << bytes << ">" << endl
6911 << "]>;" << endl << endl;
6912
6913 // Function argument value types.
6914 os << "// Function argument value types." << endl;
6915 os << "def CC_TCE : CallingConv<[" << endl;
6916 if (mach_.is64bit()) {
6917 os << " CCIfType<[i1, i8, i16, i32], CCPromoteToType<i64>>," << endl
6918 << " CCIfType<[i64], CCAssignToReg<[IRES0]>>," << endl << endl;
6919
6920 for (unsigned int i = 4; i < (3 + argRegCount_); i++) {
6921 os << " CCIfType<[i64], CCAssignToReg<[A" << i << "]>>," << endl;
6922 }
6923
6924 } else {
6925 os << " CCIfType<[i1, i8, i16], CCPromoteToType<i32>>," << endl
6926 << " CCIfType<[i32], CCAssignToReg<[IRES0]>>," << endl << endl;
6927
6928 for (unsigned int i = 4; i < (3 + argRegCount_); i++) {
6929 os << " CCIfType<[i32], CCAssignToReg<[A" << i << "]>>," << endl;
6930 }
6931 }
6932
6933 if (mach_.is64bit()) {
6934 os << " // 64-bit integer values get stored in stack slots that are"
6935 << endl
6936 << " // 8 bytes insize and 8-byte aligned." << endl
6937 << " CCIfType<[i64, f64, f32], CCAssignToStack<8, 8>>,"
6938 << endl << endl;
6939 } else {
6940 os << " // Integer values get stored in stack slots that are" << endl
6941 << " // 4 bytes insize and 4-byte aligned." << endl
6942 << " CCIfType<[i32, f32], CCAssignToStack<4, 4>>," << endl << endl;
6943 }
6944 os << " // Double values get stored in stack slots that are" << endl
6945 << " // 8 bytes in size and 8-byte aligned." << endl
6946 << " CCIfType<[f64], CCAssignToStack<8, 8>>";
6947
6948 if (vRegClasses_.size() > 0) {
6949 os << ",";
6950 }
6951 os << endl << endl;
6952
6953 os << " // Vector value types." << endl;
6954 for (rcIt = vRegClasses_.begin(); rcIt != vRegClasses_.end(); ++rcIt) {
6955 const TCEString& vtStr = rcIt->first;
6956 const RegisterClass& regClass = rcIt->second;
6957
6958 int byteAlignment = regClass.alignment() / 8;
6959 if (byteAlignment < bytes) {
6960 byteAlignment = bytes;
6961 }
6962
6963 os << " CCIfType<[" << vtStr << "], CCAssignToStack<"
6964 << byteAlignment << ", " << byteAlignment << ">>";
6965 if (rcIt != --vRegClasses_.end()) {
6966 os << ",";
6967 }
6968 os << endl;
6969 }
6970
6971 os << "]>;" << endl;
6972}
6973
6974void
6976 os << "//===- GenCallingConv.td - Calling Conventions TCE ---------*- "
6977 << "tablegen -*-===//" << std::endl
6978 << "// " << std::endl
6979 << "// The LLVM Compiler Infrastructure" << std::endl
6980 << "//" << std::endl
6981 << "// This file is distributed under the University of "
6982 << "Illinois Open Source" << std::endl
6983 << "// License. See LICENSE.TXT for details." << std::endl
6984 << "// " << std::endl
6985 << "//===--------------------------------------------------------"
6986 << "--------------===//" << std::endl
6987 << "//" << std::endl
6988 << "// This describes the calling conventions for the TCE "
6989 << "architectures." << std::endl
6990 << "//" << std::endl
6991 << "//===--------------------------------------------------------"
6992 << "--------------===//" << std::endl << std::endl;
6993}
6994
6995void
6996TDGen::writeArgRegsArray(std::ostream& os) {
6997 os << "#ifndef ARGREGS_HH" << std::endl
6998 << "#define ARGREGS_HH" << std::endl << std::endl
6999 << "static const unsigned ArgRegs[] = { TCE::IRES0" << std::endl;
7000 for (unsigned int i = 4; i < (3 + argRegCount_); i++) {
7001 os << ",TCE::A" << i;
7002 }
7003 os << "};" << std::endl;
7004
7005 os << "static const int argRegCount = " << argRegCount_ <<";" << std::endl
7006 << "#endif" << std::endl;
7007}
7008
7009void
7011 os <<
7012 "std::vector<unsigned>" << std::endl <<
7013 "GeneratedTCEPlugin::getParamDRegNums() const {" << std::endl <<
7014 "std::vector<unsigned> res;" << std::endl;
7015 for (unsigned int i = 4; i < argRegCount_ + 3; i++) {
7016 os << "res.push_back(TCE::A" << i << ");" << std::endl;
7017 }
7018 os << "return res;}" << std::endl;
7019}
7020
7021void
7023 os <<
7024 "std::vector<unsigned>" << std::endl <<
7025 "GeneratedTCEPlugin::getVectorRVDRegNums() const {" << std::endl <<
7026 "std::vector<unsigned> res;" << std::endl;
7027
7028 std::set<TCEString> processedRegs;
7029 for (auto rcIt : vRegClasses_) {
7030 const RegisterClass& regClass = rcIt.second;
7031
7032 int width = regClass.valueType().width();
7033 if (regClass.numberOfRegisters() > 0) {
7034 const TCEString& name = regClass.registerInfo(0).regName_;
7035 if (processedRegs.find(name) == processedRegs.end() &&
7036 width > maxScalarWidth_) {
7037 processedRegs.insert(name);
7038
7039 os << "res.push_back(TCE::" << name << ");" << std::endl;
7040 }
7041 }
7042 }
7043 os << "return res;}" << std::endl;
7044}
7045
7046// TODO: this should be based on vector widths???
7047void
7048TDGen::createGetMaxMemoryAlignment(std::ostream& os) const {
7049 if (mach_.is64bit()) {
7050 os << std::endl
7051 << "unsigned GeneratedTCEPlugin::getMaxMemoryAlignment() const {"
7052 << std::endl
7053 << "\treturn 8;"
7054 << std::endl << "}" << std::endl;
7055 } else {
7056 os << std::endl
7057 << "unsigned GeneratedTCEPlugin::getMaxMemoryAlignment() const {"
7058 << std::endl
7059 << "\treturn 4;"
7060 << std::endl << "}" << std::endl;
7061 }
7062}
7063
7064
7065void TDGen::createSelectPatterns(std::ostream& os) {
7066 os << "// Creating select patterns. " << std::endl;
7067 if (!hasSelect_) {
7068 os << "// Does not have select instr. " << std::endl;
7069 if (!hasConditionalMoves_) {
7070 std::string NEG = mach_.is64bit() ? "NEG64" : "NEG";
7071 std::string NEGOPC = mach_.is64bit() ? "NEG64ss" : "NEGrr";
7072 std::string gprRegs = mach_.is64bit() ? "R64IRegs" : "R32IRegs";
7073 std::string typeStr = mach_.is64bit() ? "ssa" : "rri";
7074 std::string typeStrInv = mach_.is64bit() ? "sas" : "rir";
7075
7076 const char* sub = mach_.is64bit() ? "SUB64" : "SUB";
7077 const char* iand = mach_.is64bit() ? "AND64" : "AND";
7078 std::string ior = mach_.is64bit() ? "IOR64" : "IOR";
7079 std::string defType = mach_.is64bit() ? "i64" : "i32";
7080 std::string andReg = mach_.is64bit() ? "AND64sss" : "ANDrrr";
7081 std::string iorReg = mach_.is64bit() ? "IOR64sss" : "IORrrr";
7082
7083 std::string iorBool = mach_.is64bit() ? "IOR64bbb" : "IORbbb";
7084 std::string andBool = mach_.is64bit() ? "AND64bbb" : "ANDbbb";
7085 std::string xorBooli = mach_.is64bit() ? "XOR64bbj" : "XORbbj";
7086
7087 bool hasNeg = opNames_.count("NEGrr");
7088
7089 std::string condRC = regs1bit_.empty() ? gprRegs : "R1Regs";
7090 std::string truncOp = regs1bit_.empty() ? std::string(iand) + typeStr : "ANDext";
7091 OperationPool opPool;
7092 std::string truncPattern = regs1bit_.empty()
7093 ? std::string("$c")
7094 : std::string("(") + truncOp + " " + condRC + ":$c" + ", 1)";
7095 std::string falseMask = getLLVMPatternWithConstants(
7096 opPool.operation(sub), typeStr, truncPattern, "1");
7097
7098 std::string trueMask = hasNeg ?
7099 std::string("(" + NEGOPC + " ") + truncPattern +
7100 std::string(")")
7102 opPool.operation(sub), typeStrInv, "0", truncPattern);
7103
7104 std::string applyTrueMaskOnImm = getLLVMPatternWithConstants(
7105 opPool.operation(iand), typeStr, trueMask, "imm:$t");
7106 std::string applyFalseMaskOnImm = getLLVMPatternWithConstants(
7107 opPool.operation(iand), typeStr, falseMask, "imm:$f");
7108
7109#if 0 // TODO: why is this commented out???
7110 if (mach_.is64bit()) {
7111 os << std::endl
7112 << "def : Pat<(i64 (select R1Regs:$c, R64Regs:$t, R64Regs:$f)), "
7113 << "(IOR64sss (AND64sss R32Regs:$t, (SUB64sas 0, (ANDext R1Regs:$c, 1))),"
7114 << "(AND64sss R32Regs:$f, (SUB64ssa (ANDext R1Regs:$c, 1), 1)))>;"
7115 << std::endl << std::endl
7116
7117 << "def : Pat<(i64 (select R1Regs:$c, (i64 imm:$t),(i64 imm:$f))),"
7118 << "(IOR64sss (AND64ssa (SUB64sas 0, (ANDext R1Regs:$c, 1)), imm:$t),"
7119 << "(AND64ssa (SUB64ssa (ANDext R1Regs:$c, 1), 1), imm:$f))>;"
7120 << std::endl << std::endl
7121
7122 << "def : Pat<(i64 (select R1Regs:$c, R64Regs:$t, (i64 imm:$f))),"
7123 << "(IOR64sss (AND64sss (SUB64sas 0, (ANDext R1Regs:$c, 1)), R32Regs:$t),"
7124 << "(AND64ssa (SUB64ssa (ANDext R1Regs:$c, 1), 1), imm:$f))>;"
7125 << std::endl << std::endl
7126
7127 << "def : Pat<(i64 (select R1Regs:$c, (i64 imm:$t), R64Regs:$f)),"
7128 << "(IOR64sss (AND64ssa (SUB64sas 0, (ANDext R1Regs:$c, 1)), imm:$t),"
7129 << "(AND64sss (SUB64ssa (ANDext R1Regs:$c, 1), 1), R32Regs:$f))>;"
7130 << std::endl << std::endl;
7131
7132 os << std::endl
7133 << "def : Pat<(i64 (select R1Regs:$c, R64Regs:$t, R64Regs:$f)), "
7134 << "(IOR64sss (AND64sss R64Regs:$t, (SUB64sas 0, (ANDext R1Regs:$c, 1))),"
7135 << "(AND64sss R64Regs:$f, (SUB64ssa (ANDext R1Regs:$c, 1), 1)))>;"
7136 << std::endl << std::endl
7137
7138 << "def : Pat<(i64 (select R1Regs:$c, (i64 imm:$t),(i64 imm:$f))),"
7139 << "(IOR64sss (AND64ssa (SUB64sas 0, (ANDext R1Regs:$c, 1)), imm:$t),"
7140 << "(AND64ssa (SUB64ssa (ANDext R1Regs:$c, 1), 1), imm:$f))>;"
7141 << std::endl << std::endl
7142
7143 << "def : Pat<(i64 (select R1Regs:$c, R64Regs:$t, (i64 imm:$f))),"
7144 << "(IOR64sss (AND64sss (SUB64sas 0, (ANDext R1Regs:$c, 1)), R64Regs:$t),"
7145 << "(AND64ssa (SUB64ssa (ANDext R1Regs:$c, 1), 1), imm:$f))>;"
7146 << std::endl << std::endl
7147
7148 << "def : Pat<(i64 (select R1Regs:$c, (i64 imm:$t), R64Regs:$f)),"
7149 << "(IOR64sss (ANDssa (SUB64sas 0, (ANDext R1Regs:$c, 1)), imm:$t),"
7150 << "(ANDsss (SUBssa (ANDext R1Regs:$c, 1), 1), R64Regs:$f))>;"
7151 << std::endl << std::endl
7152
7153 << "def : Pat<(i1 (select R1Regs:$c, R1Regs:$t, R1Regs:$f)),"
7154 << "(IOR64bbb (AND64bbb R1Regs:$c, R1Regs:$t), "
7155 << "(AND64bbb (XOR64bbj R1Regs:$c, 1), R1Regs:$f))>;"
7156 << std::endl << std::endl
7157
7158 << "def : Pat<(i1 (select R1Regs:$c, (i1 0), R1Regs:$f)),"
7159 << "(AND64bbb (XOR64bbj R1Regs:$c, 1), R1Regs:$f)>;"
7160 << std::endl << std::endl
7161
7162 << "def : Pat<(i1 (select R1Regs:$c, R1Regs:$t, (i1 -1))),"
7163 << "(IOR64bbb (AND64bbb R1Regs:$c, R1Regs:$t),"
7164 << "(XOR64bbj R1Regs:$c, 1))>;"
7165 << std::endl << std::endl;
7166 } //else {
7167#endif
7168
7169 if (mach_.is64bit()) {
7170 // optimize select with zero.
7171 os << "def : Pat<(i64 (select "
7172 << condRC << ":$c, R64Regs:$t, (i64 0)))," << std::endl
7173 << " (AND64sss "
7174 << trueMask << ", R64Regs:$t)>;"
7175 << std::endl << std::endl
7176
7177 << "def : Pat<(i64 (select "
7178 << condRC << ":$c, (i64 0), R64Regs:$f))," << std::endl
7179 << "(AND64sss " << falseMask << ", R64Regs:$f)>;"
7180 << std::endl << std::endl;
7181
7182 // also select with zero and some other imm
7183 os << "def : Pat<(i64 (select "
7184 << condRC << ":$c, (i64 imm:$t),(i64 0)))," << std::endl
7185 << " " << applyTrueMaskOnImm << ">;"
7186 << std::endl << std::endl;
7187
7188 os << "def : Pat<(i64 (select "
7189 << condRC << ":$c, (i64 0),(i64 imm:$f)))," << std::endl
7190 << " " << applyFalseMaskOnImm << ">;"
7191 << std::endl << std::endl;
7192 } else {
7193 // optimize select with zero.
7194 os << "def : Pat<(i32 (select "
7195 << condRC << ":$c, R32Regs:$t, (i32 0)))," << std::endl
7196 << " (ANDrrr "
7197 << trueMask << ", R32Regs:$t)>;"
7198 << std::endl << std::endl
7199
7200 << "def : Pat<(i32 (select "
7201 << condRC << ":$c, (i32 0), R32Regs:$f))," << std::endl
7202 << "(ANDrrr " << falseMask << ", R32Regs:$f)>;"
7203 << std::endl << std::endl;
7204
7205 // also select with zero and some other imm
7206 os << "def : Pat<(i32 (select "
7207 << condRC << ":$c, (i32 imm:$t),(i32 0)))," << std::endl
7208 << " " << applyTrueMaskOnImm << ">;"
7209 << std::endl << std::endl;
7210
7211 os << "def : Pat<(i32 (select "
7212 << condRC << ":$c, (i32 0),(i32 imm:$f)))," << std::endl
7213 << " " << applyFalseMaskOnImm << ">;"
7214 << std::endl << std::endl;
7215 }
7216
7217
7218 // TODO: similar patterns could be made with -1, avoiding one AND?
7219
7220 // then the more generic ones
7221 os << std::endl
7222 << "def : Pat<(" << defType << " (select "
7223 << condRC << ":$c, " << gprRegs << ":$t, " << gprRegs << ":$f)), " << std::endl
7224 << " (" << iorReg << " (" << andReg << " " << gprRegs << ":$t, "
7225 << trueMask << "),"
7226 << "(" << andReg << " " << gprRegs << ":$f, " << falseMask << "))>;"
7227 << std::endl << std::endl
7228
7229 << "def : Pat<(" << defType << " (select "
7230 << condRC << ":$c, (" << defType << " imm:$t),(" << defType << " imm:$f)))," << std::endl
7231 << " (" << iorReg << " " << applyTrueMaskOnImm << ","
7232 << applyFalseMaskOnImm << ")>;"
7233 << std::endl << std::endl
7234
7235 << "def : Pat<(" << defType << " (select "
7236 << condRC << ":$c, " << gprRegs << ":$t, (" << defType << " imm:$f)))," << std::endl
7237 << " (" << iorReg << " (" << andReg << " "
7238 << trueMask << ", " << gprRegs << ":$t)," << applyFalseMaskOnImm << ")>;"
7239 << std::endl << std::endl
7240
7241 << "def : Pat<(" << defType << " (select "
7242 << condRC << ":$c, (" << defType << " imm:$t), " << gprRegs << ":$f))," << std::endl
7243 << " (" << iorReg << " " << applyTrueMaskOnImm << ","
7244 << "(" << andReg << " " << falseMask << ", " << gprRegs << ":$f))>;"
7245 << std::endl << std::endl;
7246
7247 if (!regs1bit_.empty()) {
7248 os << "def : Pat<(i1 (select R1Regs:$c, R1Regs:$t, R1Regs:$f)),"
7249 << std::endl
7250 << " (" << iorBool << " (" << andBool << " R1Regs:$c, R1Regs:$t), "
7251 << "(" << andBool << " (" << xorBooli << " R1Regs:$c, 1), R1Regs:$f))>;"
7252 << std::endl << std::endl
7253
7254 << "def : Pat<(i1 (select R1Regs:$c, (i1 0), R1Regs:$f)),"
7255 << std::endl
7256 << " (" << andBool << " (" << xorBooli << " R1Regs:$c, 1), R1Regs:$f)>;"
7257 << std::endl << std::endl
7258
7259 << "def : Pat<(i1 (select R1Regs:$c, R1Regs:$t, (i1 -1))),"
7260 << std::endl
7261 << " (" << iorBool << " (" << andBool << " R1Regs:$c, R1Regs:$t),"
7262 << "(" << xorBooli << " R1Regs:$c, 1))>;"
7263 << std::endl << std::endl;
7264 }
7265
7266 os << "def : Pat<(f32 (select " << condRC << ":$c, "
7267 "FPRegs:$t,FPRegs:$f))," << std::endl
7268 << " (IORfff (ANDfff FPRegs:$t, (SUBfir 0, "
7269 << truncPattern << ")),"
7270 << "(ANDfff FPRegs:$f, (SUBfri "
7271 << truncPattern << ",1)))>;"
7272 << std::endl << std::endl
7273
7274 << "def : Pat<(f16 (select " << condRC << ":$c, "
7275 "R32HFPRegs:$t, R32HFPRegs:$f))," << std::endl
7276 << " (IORhhh (ANDhhh R32HFPRegs:$t, (SUBhir 0, "
7277 << truncPattern << ")),"
7278 << "(ANDhhh R32HFPRegs:$f, (SUBhri "
7279 << truncPattern << ",1)))>;"
7280 << std::endl << std::endl;
7281// }
7282 } else { // has conditional moves.
7283 opNames_["SELECT_I1bb"] = "CMOV_SELECT";
7284 opNames_["SELECT_I1bj"] = "CMOV_SELECT";
7285 opNames_["SELECT_I1jb"] = "CMOV_SELECT";
7286 opNames_["SELECT_I1jj"] = "CMOV_SELECT";
7287 opNames_["SELECT_I32rr"] = "CMOV_SELECT";
7288 opNames_["SELECT_I32ir"] = "CMOV_SELECT";
7289 opNames_["SELECT_I32ri"] = "CMOV_SELECT";
7290 opNames_["SELECT_I32ii"] = "CMOV_SELECT";
7291 opNames_["SELECT_F32"] = "CMOV_SELECT";
7292 opNames_["SELECT_F16"] = "CMOV_SELECT";
7293
7294 // TODO: why does this break??
7295 os << " let isSelect = 1 in {" << std::endl;
7296
7297 if (mach_.is64bit()) {
7298 opNames_["SELECT_I64rr"] = "CMOV_SELECT";
7299 opNames_["SELECT_I64ir"] = "CMOV_SELECT";
7300 opNames_["SELECT_I64ri"] = "CMOV_SELECT";
7301 opNames_["SELECT_I64ii"] = "CMOV_SELECT";
7302 opNames_["SELECT_F64"] = "CMOV_SELECT";
7303
7304
7305
7306 os << "def SELECT_I64rr : InstTCE<(outs R64IRegs:$dst),"
7307 << "(ins R1Regs:$c, R64IRegs:$T, R64IRegs:$F),"
7308 << "\"# SELECT_I64 PSEUDO!\","
7309 << "[(set R64IRegs:$dst,"
7310 << "(select R1Regs:$c, R64IRegs:$T, R64IRegs:$F))]>;"
7311 << std::endl << std::endl
7312
7313 << "def SELECT_I64ri : InstTCE<(outs R64IRegs:$dst),"
7314 << "(ins R64IRegs:$c, R64IRegs:$T, i64imm:$F),"
7315 << "\"# SELECT_I64 PSEUDO!\","
7316 << "[(set R64IRegs:$dst,"
7317 << "(select R64IRegs:$c, R64IRegs:$T, (i64 imm:$F)))]>;"
7318 << std::endl << std::endl
7319
7320 << "def SELECT_I64ir : InstTCE<(outs R64IRegs:$dst),"
7321 << "(ins R64IRegs:$c, i64imm:$T, R64IRegs:$F),"
7322 << "\"# SELECT_I64 PSEUDO!\","
7323 << "[(set R64IRegs:$dst,"
7324 << "(select R64IRegs:$c, (i64 imm:$T), R64IRegs:$F))]>;"
7325 << std::endl << std::endl
7326
7327 << "def SELECT_I64ii : InstTCE<(outs R64IRegs:$dst),"
7328 << "(ins R64IRegs:$c, i64imm:$T, i64imm:$F),"
7329 << "\"# SELECT_I64 PSEUDO!\","
7330 << "[(set R64IRegs:$dst,"
7331 << "(select R64IRegs:$c, (i64 imm:$T), (i64 imm:$F)))]>;"
7332 << std::endl << std::endl
7333
7334 << "def SELECT_F64 : InstTCE<(outs R64DFPRegs:$dst),"
7335 << "(ins R1Regs:$c, R64DFPRegs:$T, R64DFPRegs:$F),"
7336 << "\"# SELECT_F64 PSEUDO!\","
7337 << "[(set R64DFPRegs:$dst,"
7338 << "(select R1Regs:$c, R64DFPRegs:$T, R64DFPRegs:$F))]>;"
7339 << std::endl << std::endl;
7340 }
7341
7342 os << "def SELECT_I1bb : InstTCE<(outs R1Regs:$dst),"
7343 << "(ins GuardRegs:$c, R1Regs:$T, R1Regs:$F),"
7344 << "\"# SELECT_I1 PSEUDO!\","
7345 << " [(set R1Regs:$dst,"
7346 << "(select GuardRegs:$c, R1Regs:$T, R1Regs:$F))]>;"
7347 << std::endl << std::endl
7348
7349 << "def SELECT_I1bj : InstTCE<(outs R1Regs:$dst),"
7350 << " (ins GuardRegs:$c, R1Regs:$T, i1imm:$F),"
7351 << "\"# SELECT_I1 PSEUDO!\","
7352 << "[(set R1Regs:$dst,"
7353 << "(select GuardRegs:$c, R1Regs:$T, (i1 imm:$F)))]>;"
7354 << std::endl << std::endl
7355
7356 << "def SELECT_I1jb : InstTCE<(outs R1Regs:$dst),"
7357 << "(ins GuardRegs:$c, i1imm:$T, R1Regs:$F),"
7358 << "\"# SELECT_I1 PSEUDO!\","
7359 << "[(set R1Regs:$dst,"
7360 << "(select GuardRegs:$c, (i1 imm:$T), R1Regs:$F))]>;"
7361 << std::endl << std::endl
7362
7363 << "def SELECT_I1jj : InstTCE<(outs R1Regs:$dst),"
7364 << "(ins GuardRegs:$c, i1imm:$T, i1imm:$F),"
7365 << "\"# SELECT_I1 PSEUDO!\","
7366 << "[(set R1Regs:$dst,"
7367 << "(select GuardRegs:$c, (i1 imm:$T), (i1 imm:$F)))]>;"
7368 << std::endl << std::endl
7369
7370 << "def SELECT_I32rr : InstTCE<(outs R32IRegs:$dst),"
7371 << "(ins GuardRegs:$c, R32IRegs:$T, R32IRegs:$F),"
7372 << "\"# SELECT_I32 PSEUDO!\","
7373 << "[(set R32IRegs:$dst,"
7374 << "(select GuardRegs:$c, R32IRegs:$T, R32IRegs:$F))]>;"
7375 << std::endl << std::endl
7376// select with the cond in an i32 (produced by expanded vselects with i32 cond vectors)
7377
7378 << "def SELECT_I32ri : InstTCE<(outs R32IRegs:$dst),"
7379 << "(ins R32IRegs:$c, R32IRegs:$T, i32imm:$F),"
7380 << "\"# SELECT_I32 PSEUDO!\","
7381 << "[(set R32IRegs:$dst,"
7382 << "(select R32IRegs:$c, R32IRegs:$T, i32MoveImm:$F))]>;"
7383 << std::endl << std::endl
7384
7385 << "def SELECT_I32ir : InstTCE<(outs R32IRegs:$dst),"
7386 << "(ins R32IRegs:$c, i32imm:$T, R32IRegs:$F),"
7387 << "\"# SELECT_I32 PSEUDO!\","
7388 << "[(set R32IRegs:$dst,"
7389 << "(select R32IRegs:$c, i32MoveImm:$T, R32IRegs:$F))]>;"
7390 << std::endl << std::endl
7391
7392 << "def SELECT_I32ii : InstTCE<(outs R32IRegs:$dst),"
7393 << "(ins R32IRegs:$c, i32imm:$T, i32imm:$F),"
7394 << "\"# SELECT_I32 PSEUDO!\","
7395 << "[(set R32IRegs:$dst,"
7396 << "(select R32IRegs:$c, i32MoveImm:$T, i32MoveImm:$F))]>;"
7397 << std::endl << std::endl
7398
7399 << "def SELECT_F32 : InstTCE<(outs FPRegs:$dst),"
7400 << "(ins GuardRegs:$c, FPRegs:$T, FPRegs:$F),"
7401 << "\"# SELECT_F32 PSEUDO!\","
7402 << "[(set FPRegs:$dst,"
7403 << "(select GuardRegs:$c, FPRegs:$T, FPRegs:$F))]>;"
7404 << std::endl << std::endl
7405
7406 << "def SELECT_F16 : InstTCE<(outs HFPRegs:$dst),"
7407 << "(ins GuardRegs:$c, HFPRegs:$T, HFPRegs:$F),"
7408 << "\"# SELECT_F16 PSEUDO!\","
7409 << "[(set HFPRegs:$dst, "
7410 << "(select GuardRegs:$c, HFPRegs:$T, HFPRegs:$F))]>;"
7411 << std::endl << std::endl;
7412
7413 os << "}" << std::endl << std::endl;
7414
7415 if (mach_.is64bit()) {
7416 os << "def : Pat<(i64 (select R64IRegs:$c, R64IRegs:$T, R64IRegs:$F)),"
7417 << "(SELECT_I64rr (MOVI64I1ss R64Regs:$c),"
7418 << "R64IRegs:$T, R64IRegs:$F)>;"
7419 << std::endl << std::endl;
7420 }
7421
7422 os << "def : Pat<(i32 (select R32IRegs:$c, R32IRegs:$T, R32IRegs:$F)),"
7423 << "(SELECT_I32rr (MOVI32I1rr R32Regs:$c),"
7424 << "R32IRegs:$T, R32IRegs:$F)>;"
7425 << std::endl << std::endl;
7426
7427 }
7428 } else {
7429 os << "// Has select instr!. " << std::endl;
7430 }
7431 std::map<TCEString, RegisterClass>::const_iterator it;
7432 for (it = vRegClasses_.begin(); it != vRegClasses_.end(); ++it) {
7433 const RegisterClass& regClass = it->second;
7434 TCEString regClassName = regClass.name();
7435 ValueType valType = regClass.valueType();
7436 TCEString valTypeName = valType.valueTypeStr();
7437
7438 os << "def SELECT_" << valTypeName << " : InstTCE<(outs "
7439 << regClassName << ":$dst), (ins R1Regs:$c, " << regClassName
7440 << ":$T, " << regClassName << ":$F), \"\","
7441 << "[(set " << regClassName << ":$dst,"
7442 << "(select R1Regs:$c, " << regClassName << ":$T, " << regClassName
7443 << ":$F))]>;" << std::endl
7444 << std::endl;
7445
7446 opNames_["SELECT_" + valTypeName] = "CMOV_SELECT";
7447 }
7448}
7449
7450/**
7451 * Generates llvm patterns for constants which are not supported directly as
7452 * immediates by the target machine.
7453 *
7454 * For example, if a target does not sign extending immediates, a pattern is
7455 * generated that transforms negative constants C to (SUB 0, -C).
7456 */
7457void
7459
7460 // TODO: this is used when when not needed!
7461 // creating unnecessary NEG operations!
7462
7463 // LLVM XForm fragments //
7464
7465 // Transformation functions definitions that creates new constants
7466 // from unsupported constants.
7467 os << std::endl << "// Arithmetic negation XForm fragment."
7468 << std::endl << "def aneg_xform : SDNodeXForm<imm, [{"
7469 << std::endl << " return CurDAG->getTargetConstant("
7470 << std::endl << " -(N->getZExtValue()), SDLoc(N), MVT::i32);"
7471 << std::endl << "}]>;"
7472 << std::endl << std::endl;
7473
7474 // Constant select operand definitions //
7475
7476 // Used in Constant materialization patterns to select the constant values
7477 // that are valid for the pattern transformation. The predicate must
7478 // test that the original constant can be accepted by the materialization
7479 // pattern itself and test that the resulted constants by XForms are
7480 // supported too by the target machine.
7481
7482 // Negative constant materialization: C -> NEG(-C) or C -> SUB(0, -C)
7483 // selecting the cheapest.
7484 std::vector<std::string> ops;
7485 if (opNames_.count("NEGri")) ops.push_back("NEG");
7486 if (opNames_.count("SUBrri")) ops.push_back("SUB");
7487 for (auto op : ops) {
7488 // Predicate that accepts the negative constants
7489 std::string predicate = "Imm < 0";
7490 std::pair<int64_t, int64_t> tmp = immInfo_->immediateValueBounds(
7491 ImmInfoKey{op , 1} , 32);
7492 if (tmp.second < 2) continue;
7493
7494 predicate += " && Imm >= -" + Conversion::toString(tmp.second-1);
7495
7496 writeImmediateDef(os, "minus_i32imm", "i32", predicate);
7497 // store predicates for the materialization queries by ISelLowering,
7498 // where decisions to bail unsupported constants to constant pool are
7499 // made. The stored predicates are written to Backend.inc later on.
7500 constantMaterializationPredicates_.push_back(predicate);
7501
7502 os << std::endl << "def : Pat<(i32 minus_i32imm:$imm)," << std::endl;
7503 if (op == "NEG") {
7504 os << " (NEGri (aneg_xform imm:$imm))>;";
7505 } else if (op == "SUB") {
7506 os << " (SUBrri (MOVI32ri 0), (aneg_xform imm:$imm))>;";
7507 }
7508 os << std::endl;
7509 break; // We need only the cheapest materialization pattern.
7510 }
7511}
7512
7513/**
7514 * Writes query method for retrieving LLVM instruction for pointer adjustment
7515 * and suitable offset value.
7516 *
7517 * Some machines may not SUBrri definition (second operand can not take an
7518 * immediate) and, therefore, pointer adjustments must use other operation
7519 * for it.
7520 */
7521void
7523
7524 TCEString ADDIMM = mach_.is64bit() ? "ADD64ssa" : "ADDrri";
7525 TCEString SUBIMM = mach_.is64bit() ? "SUB64ssa" : "SUBrri";
7526
7527
7528
7529 boost::format queryTmpl(
7530 "// <MI opcode, adjusted offset>\n"
7531 "std::tuple<int, int> GeneratedTCEPlugin::getPointerAdjustment(\n"
7532 " int offset) const {\n"
7533 " if (offset > 0) // Adjust pointer up.\n"
7534 " return std::make_tuple(TCE::%1%, offset);\n"
7535 " else\n"
7536 " return std::make_tuple(TCE::%2%, %3%);\n"
7537 "}\n");
7538
7539 // Prefer non-negative offset
7540 if (opNames_.count(SUBIMM)) {
7541 os << queryTmpl % ADDIMM % SUBIMM % "-offset" << std::endl;
7542 return;
7543 } else if (opNames_.count("ADDrri")) {
7544 os << queryTmpl % ADDIMM % ADDIMM % "offset" << std::endl;
7545 return;
7546 }
7547
7550 "The machine is missing ADD or SUB operation with direct\n"
7551 "immediate source for pointer adjustment operations.");
7552 return;
7553}
7554
7555
7556/**
7557 * Returns llvm predicate expression for short immediate constraint.
7558 */
7559std::string
7561 int64_t lowerBoundInclusive,
7562 uint64_t upperBoundInclusive) {
7563
7564 // If can transport any 64-bit imm, no need for any checks.
7565 if (upperBoundInclusive == UINT64_MAX ||
7566 lowerBoundInclusive == INT64_MIN) {
7567 return std::string("(true)");
7568 }
7569
7570 return std::string("(")
7571 + Conversion::toString(lowerBoundInclusive) + "ll"
7572 + " <= Imm && Imm <= "
7573 + Conversion::toString(upperBoundInclusive) + "ll)";
7574}
7575
7576/**
7577 * Returns corresponding immediate operand name for the emulated operation.
7578 *
7579 * @param dag The emulation code of the emulated operation.
7580 * @param operand The operand.
7581 * @return The operand immediate name if found. Otherwise return empty string.
7582 */
7583std::string
7585 const OperationDAG& dag,
7586 const Operand& operand) {
7587
7588 for (const auto& sourceNode : dag.rootNodes()) {
7589 const TerminalNode* sourceTerminal =
7590 dynamic_cast<TerminalNode*>(sourceNode);
7591
7592 if (sourceTerminal == nullptr) continue;
7593
7594 for (const auto& destEdge : dag.outEdges(*sourceTerminal)) {
7595 const OperationNode* opNode =
7596 dynamic_cast<OperationNode*>(&dag.headNode(*destEdge));
7597
7598 assert(opNode != nullptr &&
7599 "TerminalNode points to other than OperandNode.");
7600 const Operation& operation = opNode->referencedOperation();
7601 ImmInfoKey key = ImmInfo::key(operation, operand);
7602 if (immOperandDefs_.count(key)) {
7603 return immOperandDefs_.at(key);
7604 } else {
7605 return "";
7606 }
7607 }
7608 }
7609 return "";
7610}
7611
7612/**
7613 * Checks if the operation can have the specified immediate operands.
7614 *
7615 */
7616bool
7618 const Operation& operation,
7619 const std::string& operandTypes) const {
7620
7621 assert(static_cast<int>(operandTypes.size()) >= operation.operandCount());
7622
7623 for (int i = 0 ; i < operation.numberOfInputs(); i++) {
7624 if (operandTypes.at(i + operation.numberOfOutputs()) != OT_IMM_INT) {
7625 continue;
7626 }
7627
7628 const Operand& operand = operation.operand(i+1);
7629
7630 // Kludge fix for ADDri/MEMri operands. LLVM wants some times to select
7631 // store/load instruction, where the address operand is immediate.
7632 // However, the machine may not have capability to directly transport
7633 // immediate to the address operand. Considering the case as illegal
7634 // will reject operation definitions using ADDri/MEMri operands and
7635 // breaks the instruction selection later on. Temporarily accept
7636 // ADDri/MEMri operands until the issue is fixed.
7637 if (operand.isAddress()) {
7638 continue;
7639 }
7640
7641 if (immInfo_->count(operation, operand) == 0) {
7642 for (int swappableWith : operand.swap()) {
7643 const Operand& otherOperand = operation.operand(swappableWith);
7644 if (immInfo_->count(operation, otherOperand)
7645 && operation.name() != "EQ"
7646 && operation.name() != "NE") {
7647 // ^ EQ and NE are not commutative in LLVM
7648 return true;
7649 }
7650 }
7651 return false;
7652 }
7653 }
7654
7655 return true;
7656}
7657
7658
7659/**
7660 * Returns true if the instruction can be predicated.
7661 *
7662 * TODO
7663 */
7664bool
7665TDGen::canBePredicated(Operation& /*op*/, const std::string& operandTypes) {
7666
7667 // Predicating operands with immediates can currently lead to
7668 // unschedulable code in case there's no bus that has both the
7669 // predicate and the immediate transfer capability. Disable
7670 // generating the predicated versions for immediate operand
7671 // patterns for now.
7672 if (operandTypes.find(OT_IMM_INT) != std::string::npos) return false;
7673
7674 if (hasConditionalMoves_) return true;
7675
7676 return false;
7677}
7678
7679/**
7680 * Returns OSAL operation names valid for stack accesses.
7681 *
7682 * @param mach The target machine.
7683 */
7684std::vector<std::string>
7686
7687 using namespace TTAMachine;
7688
7689 std::vector<std::string> opcodes;
7690
7691 auto collectMemoryOps = [](
7692 std::vector<std::string>& newOpcodes,
7693 const FunctionUnit& fu) -> void {
7694
7695 for (int i = 0; i < fu.operationCount(); i++) {
7696 const Operation& op = MachineInfo::osalOperation(*fu.operation(i));
7697 if (!op.readsMemory() && !op.writesMemory()) {
7698 continue;
7699 }
7700 newOpcodes.push_back(StringTools::stringToUpper(op.name()));
7701 }
7702 };
7703
7704 std::map<const AddressSpace*, std::set<const FunctionUnit*>>
7705 addrSpaceLsuMap;
7706 for (const FunctionUnit* fu : mach.functionUnitNavigator()) {
7707 if (fu->hasAddressSpace()) {
7708 addrSpaceLsuMap[fu->addressSpace()].insert(fu);
7709 }
7710 }
7711
7712 const int stackAddressSpaceId = 0;
7713 if (addrSpaceLsuMap.size() == 1) {
7714 // Only one data address space. Stack resides there.
7715 for (auto lsu : addrSpaceLsuMap.begin()->second) {
7716 collectMemoryOps(opcodes, *lsu);
7717 }
7718 } else {
7719 // Multiple data address spaces. Find LSUs having the stack address
7720 // space ID.
7721 for (auto asLsusPair : addrSpaceLsuMap) {
7722 if (asLsusPair.first->hasNumericalId(stackAddressSpaceId)) {
7723 for (auto lsu : asLsusPair.second) {
7724 collectMemoryOps(opcodes, *lsu);
7725 }
7726 break;
7727 }
7728 }
7729 }
7730
7731 return opcodes;
7732}
7733
7734/**
7735 * Returns LLVM pattern for the expression with constant value(s) supported by
7736 * target machine.
7737 *
7738 * For example, for pattern (SUBrri (foo ...), 123) the method returns
7739 * (SUBrrr (foo ...), (MOVI32ri 123)) if the target machine can not supply
7740 * the constant "123" as an immediate.
7741 *
7742 * The method should be called after all operation definitions have been
7743 * created (after all calls to writeOperationDef()).
7744 *
7745 * Return empty string if the given pattern can not be handled because:
7746 * - Operation is not supported by target machine.
7747 *
7748 * @param op The operation.
7749 * @param operandTypes The preferred operand types.
7750 * @param operand0 The pattern for the first operand or constant indicated by
7751 * operandTypes.
7752 * @param operand1 The pattern for the second operand or constant indicated by
7753 * operandTypes.
7754 */
7757 const Operation& op, const std::string& operandTypes,
7758 const std::string& operand0,
7759 const std::string& operand1) const {
7760
7761 //TODO If operation is not supported, try to replace it with an emulation
7762 // pattern first and then deal with the new patterns with constant
7763 // operands (and take account possible infinite recursion).
7764 //TODO Cache the calculated results?
7765
7766 assert(op.numberOfInputs() == 2);
7767
7768 auto makePattern = [](
7769 const std::string& opc,
7770 const std::string& opdTypes,
7771 const std::string& operand0,
7772 const std::string& operand1) -> TCEString {
7773 return std::string("(") + opc + opdTypes + " " + operand0
7774 + ", " + operand1 + ")";
7775 };
7776
7777 std::string opc = StringTools::stringToUpper(op.name());
7778 const std::string outputOpdTypes = operandTypes.substr(
7779 0, op.numberOfOutputs());
7780 const std::string inputOpdTypes = operandTypes.substr(
7781 op.numberOfOutputs());
7782 assert(inputOpdTypes.size() == 2);
7783 const auto regOperandsOnly = operandTypesToRegisters(operandTypes);
7784 if (!opNames_.count(opc + regOperandsOnly)) {
7785 // Operation is not supported at all by the target machine.
7786 return "";
7787 }
7788
7789 if (opNames_.count(opc + operandTypes)) {
7790 // Supported as is.
7791 return makePattern(opc, operandTypes, operand0, operand1);
7792 }
7793
7794 std::vector<std::string> supportedOperandTypes;
7795 for (auto i = 0u; i < inputOpdTypes.size(); i++) {
7796 std::string oneInputChanged = inputOpdTypes;
7797 oneInputChanged[i] = operandTypeToRegister(oneInputChanged[i]);
7798 if (oneInputChanged == inputOpdTypes) continue;
7799 if (opNames_.count(opc + outputOpdTypes + oneInputChanged)) {
7800 supportedOperandTypes.push_back(oneInputChanged);
7801 }
7802 }
7803
7804 supportedOperandTypes.push_back(regOperandsOnly);
7805
7806 std::vector<const std::string*> inputOpdValues{&operand0, &operand1};
7807
7808 // Now legalize pattern by changing unsupported immediate operands with
7809 // immediate moves.
7810 for (const auto& supportedOpdType : supportedOperandTypes) {
7811
7812 // Loop throught immediate opd types. Check if constant is encodable
7813 // for the operation.
7814 bool isSupported = true;
7815 for (auto i = 0u; i < supportedOpdType.size(); i++) {
7816 auto& opdType = supportedOpdType.at(i);
7817 auto osalOpdIdx = i - op.numberOfInputs() + 1;
7818
7819 bool ok = false;
7820 switch (opdType) {
7821 default:
7822 ok = true; // Ok. Not immediate type.
7823 break;
7824 case OT_IMM_INT: {
7825 bool isOperandReference =
7826 inputOpdValues.at(i)->find(":$") != std::string::npos;
7827 if (isOperandReference) {
7828 // Size of the constant is not known, must expect the
7829 // worst.
7830 ok = false;
7831 break;
7832 }
7833 int64_t value = Conversion::toInt(
7834 *inputOpdValues.at(i));
7835 ok = immInfo_->canTakeImmediate(op, osalOpdIdx, value,
7836 32);
7837 }
7838 break;
7839 case OT_IMM_FP:
7841 op, osalOpdIdx, 32);
7842 break;
7843 case OT_IMM_HFP:
7845 op, osalOpdIdx, 16);
7846 break;
7847 case OT_IMM_BOOL:
7849 op, osalOpdIdx, 1);
7850 break;
7851 }
7852 if (!ok) {
7853 isSupported = false;
7854 break;
7855 }
7856 }
7857
7858 if (!isSupported) continue;
7859
7860 std::string result = std::string("(") + opc + outputOpdTypes
7861 + supportedOpdType + " ";
7862 if (supportedOpdType.at(0) == inputOpdTypes.at(0)) {
7863 result += *inputOpdValues.at(0);
7864 } else {
7865 result += getMovePattern(
7866 inputOpdTypes.at(0), *inputOpdValues.at(0));
7867 }
7868 for (auto i = 1u; i < supportedOpdType.size(); i++) {
7869 result += ", ";
7870 if (supportedOpdType.at(i) == inputOpdTypes.at(i)) {
7871 result += *inputOpdValues.at(i);
7872 } else {
7873 result += getMovePattern(
7874 inputOpdTypes.at(i), *inputOpdValues.at(i));
7875 }
7876 }
7877 result += ")";
7878 return result;
7879 }
7880
7881 return "";
7882}
7883
7884std::string
7885TDGen::operandTypesToRegisters(const std::string& opdTypes) const {
7886 std::string result(opdTypes);
7887 for (char& type : result) {
7888 type = operandTypeToRegister(type);
7889 }
7890 return result;
7891}
7892
7893char
7894TDGen::operandTypeToRegister(const char& opdType) const {
7895 switch (opdType) {
7896 case OT_IMM_INT: return OT_REG_INT; // Integer immediate.
7897 case OT_IMM_BOOL: return OT_REG_BOOL; // Boolean immediate.
7898 case OT_IMM_FP: return OT_REG_FP; // 32-bit floating point immediate.
7899 case OT_IMM_HFP: return OT_REG_HFP; // 15-bi floating point immediate.
7900 // TODO: vector immediate types.
7901 default:
7902 break;
7903 }
7904 return opdType; // Return as is (should be register type).
7905}
7906
7907
7910 const char& opdType, const std::string& inputPattern) const {
7911
7912 TCEString pat = "(MOV";
7913 // Note: This listing is incomplete.
7914 switch (opdType) {
7915 case OT_IMM_INT: // Integer immediate.
7916 pat += std::string("I32") + operandTypeToRegister(opdType) + opdType;
7917 break;
7918 case OT_REG_INT: // Integer register.
7919 pat += std::string("I32") + operandTypeToRegister(opdType) + opdType;
7920 break;
7921 case OT_IMM_BOOL: // Boolean immediate.
7922 pat += "I1ri"; //TODO: this is inconsistent
7923 break;
7924 case OT_REG_BOOL: // Boolean register.
7925 pat += "I1rr"; //TODO: this is inconsistent
7926 break;
7927 case OT_IMM_FP: // Single precision floating point immediate.
7928 case OT_REG_FP: // -||- register.
7929 pat += std::string("F32") + operandTypeToRegister(opdType) + opdType;
7930 break;
7931 case OT_IMM_HFP: // Half precision floating point immediate.
7932 case OT_REG_HFP: // -||- register.
7933 pat += std::string("F16") + operandTypeToRegister(opdType) + opdType;
7934 break;
7935 // TODO: vector register and immediate types.
7936 default:
7937 assert(false && "Handling for a type not implemented");
7938 break;
7939 }
7940 pat += " " + inputPattern + ")";
7941 return pat;
7942}
7943
7944void TDGen::writeCallSeqStart(std::ostream& os) {
7945
7946 bool is64bit = mach_.is64bit();
7947
7948 if (!is64bit) {
7949 os << "def SDT_TCECallSeqStart : SDCallSeqStart<[ SDTCisVT<0, i32>,"
7950 << "SDTCisVT<1, i32> ]>;" << std::endl << std::endl;
7951 } else {
7952 os << "def SDT_TCECallSeqStart : SDCallSeqStart<[ SDTCisVT<0, i64>,"
7953 << "SDTCisVT<1, i64> ]>;" << std::endl << std::endl;
7954 }
7955 os << "def callseq_start : SDNode<\"ISD::CALLSEQ_START\", "
7956 << "SDT_TCECallSeqStart, [SDNPHasChain, SDNPOutGlue]>;" << std::endl
7957 << std::endl
7958 << "let Defs = [SP], Uses = [SP] in {" << std::endl
7959 << "def ADJCALLSTACKDOWN : Pseudo<(outs),";
7960 if (!is64bit) {
7961 os << "(ins i32imm:$amt1, i32imm:$amt2),";
7962 } else {
7963 os << "(ins i64imm:$amt1, i64imm:$amt2),";
7964 }
7965 os << "\"# ADJCALLSTACKDOWN $amt1, $amt2\","
7966 << "[(callseq_start timm:$amt1, timm:$amt2)]>;}"
7967 << std::endl << std::endl;
7968}
7969
7970void TDGen::createBranchAnalysis(std::ostream& os) {
7971 os << "bool GeneratedTCEPlugin::analyzeCCBranch(" << std::endl
7972 << "\tllvm::MachineInstr& i," << std::endl
7973 << "\tllvm::SmallVectorImpl<llvm::MachineOperand>& cond) const {"
7974 << std::endl
7975 << std::endl;
7976
7979
7980 os << "\tif (i.getOpcode() == TCE::EQ_JUMP) {" << std::endl
7981 << "\t\tcond.push_back(i.getOperand(0));" << std::endl
7982 << "\t\tcond.push_back(i.getOperand(1));" << std::endl
7983 << "\t\tcond.push_back(MachineOperand::CreateImm(2));"
7984 << std::endl
7985 << "\t\treturn false; }" << std::endl;
7986
7987 os << "\tif (i.getOpcode() == TCE::NE_JUMP) {" << std::endl
7988 << "\t\tcond.push_back(i.getOperand(0));" << std::endl
7989 << "\t\tcond.push_back(i.getOperand(1));" << std::endl
7990 << "\t\tcond.push_back(MachineOperand::CreateImm(3));"
7991 << std::endl
7992 << "\t\treturn false; }" << std::endl;
7993
7994 os << "\tif (i.getOpcode() == TCE::GT_JUMP) {" << std::endl
7995 << "\t\tcond.push_back(i.getOperand(0));" << std::endl
7996 << "\t\tcond.push_back(i.getOperand(1));" << std::endl
7997 << "\t\tcond.push_back(MachineOperand::CreateImm(4));"
7998 << std::endl
7999 << "\t\treturn false; }" << std::endl;
8000
8001 os << "\tif (i.getOpcode() == TCE::LE_JUMP) {" << std::endl
8002 << "\t\tcond.push_back(i.getOperand(0));" << std::endl
8003 << "\t\tcond.push_back(i.getOperand(1));" << std::endl
8004 << "\t\tcond.push_back(MachineOperand::CreateImm(5));"
8005 << std::endl
8006 << "\t\treturn false; }" << std::endl;
8007
8008 os << "\tif (i.getOpcode() == TCE::GTU_JUMP) {" << std::endl
8009 << "\t\tcond.push_back(i.getOperand(0));" << std::endl
8010 << "\t\tcond.push_back(i.getOperand(1));" << std::endl
8011 << "\t\tcond.push_back(MachineOperand::CreateImm(6));"
8012 << std::endl
8013 << "\t\treturn false; }" << std::endl;
8014
8015 os << "\tif (i.getOpcode() == TCE::LEU_JUMP) {" << std::endl
8016 << "\t\tcond.push_back(i.getOperand(0));" << std::endl
8017 << "\t\tcond.push_back(i.getOperand(1));" << std::endl
8018 << "\t\tcond.push_back(MachineOperand::CreateImm(7));"
8019 << std::endl
8020 << "\t\treturn false; }" << std::endl;
8021
8022 if (opNames_.find("EQF_JUMP") != opNames_.end()) {
8023 os << "\tif (i.getOpcode() == TCE::EQF_JUMP) {" << std::endl
8024 << "\t\tcond.push_back(i.getOperand(0));" << std::endl
8025 << "\t\tcond.push_back(i.getOperand(1));" << std::endl
8026 << "\t\tcond.push_back(MachineOperand::CreateImm(8));"
8027 << std::endl
8028 << "\t\treturn false; }" << std::endl;
8029 }
8030
8031 if (opNames_.find("NEF_JUMP") != opNames_.end()) {
8032 os << "\tif (i.getOpcode() == TCE::NEF_JUMP) {" << std::endl
8033 << "\t\tcond.push_back(i.getOperand(0));" << std::endl
8034 << "\t\tcond.push_back(i.getOperand(1));" << std::endl
8035 << "\t\tcond.push_back(MachineOperand::CreateImm(9));"
8036 << std::endl
8037 << "\t\treturn false; }" << std::endl;
8038 }
8039
8040 if (opNames_.find("LEF_JUMP") != opNames_.end()) {
8041 os << "\tif (i.getOpcode() == TCE::LEF_JUMP) {" << std::endl
8042 << "\t\tcond.push_back(i.getOperand(0));" << std::endl
8043 << "\t\tcond.push_back(i.getOperand(1));" << std::endl
8044 << "\t\tcond.push_back(MachineOperand::CreateImm(10));"
8045 << std::endl
8046 << "\t\treturn false; }" << std::endl;
8047 }
8048
8049 if (opNames_.find("GEF_JUMP") != opNames_.end()) {
8050 os << "\tif (i.getOpcode() == TCE::GEF_JUMP) {" << std::endl
8051 << "\t\tcond.push_back(i.getOperand(0));" << std::endl
8052 << "\t\tcond.push_back(i.getOperand(1));" << std::endl
8053 << "\t\tcond.push_back(MachineOperand::CreateImm(10));"
8054 << std::endl
8055 << "\t\treturn false; }" << std::endl;
8056 }
8057
8058 if (opNames_.find("LTF_JUMP") != opNames_.end()) {
8059 os << "\tif (i.getOpcode() == TCE::LTF_JUMP) {" << std::endl
8060 << "\t\tcond.push_back(i.getOperand(0));" << std::endl
8061 << "\t\tcond.push_back(i.getOperand(1));" << std::endl
8062 << "\t\tcond.push_back(MachineOperand::CreateImm(12));"
8063 << std::endl
8064 << "\t\treturn false; }" << std::endl;
8065 }
8066
8067 if (opNames_.find("GTF_JUMP") != opNames_.end()) {
8068 os << "\tif (i.getOpcode() == TCE::GTF_JUMP) {" << std::endl
8069 << "\t\tcond.push_back(i.getOperand(0));" << std::endl
8070 << "\t\tcond.push_back(i.getOperand(1));" << std::endl
8071 << "\t\tcond.push_back(MachineOperand::CreateImm(13));"
8072 << std::endl
8073 << "\t\treturn false; }" << std::endl;
8074 }
8075 }
8076
8079 if (opNames_.count("TCEBREQrr")) {
8080 os << "\tif (i.getOpcode() == TCE::TCEBREQrr) {" << std::endl
8081 << "\t\tcond.push_back(i.getOperand(0));" << std::endl
8082 << "\t\tcond.push_back(i.getOperand(1));" << std::endl
8083 << "\t\tcond.push_back(MachineOperand::CreateImm(2));"
8084 << std::endl
8085 << "\t\treturn false;" << std::endl
8086 << "\t}" << std::endl;
8087
8088 os << "\tif (i.getOpcode() == TCE::TCEBREQri) {" << std::endl
8089 << "\t\tcond.push_back(i.getOperand(0));" << std::endl
8090 << "\t\tcond.push_back(i.getOperand(1));" << std::endl
8091 << "\t\tcond.push_back(MachineOperand::CreateImm(102));"
8092 << std::endl
8093 << "\t\treturn false;" << std::endl
8094 << "\t}" << std::endl;
8095 }
8096
8097 if (opNames_.count("TCEBRNErr")) {
8098 os << "\tif (i.getOpcode() == TCE::TCEBRNErr) {" << std::endl
8099 << "\t\tcond.push_back(i.getOperand(0));" << std::endl
8100 << "\t\tcond.push_back(i.getOperand(1));" << std::endl
8101 << "\t\tcond.push_back(MachineOperand::CreateImm(3));"
8102 << std::endl
8103 << "\t\treturn false;" << std::endl
8104 << "\t}" << std::endl;
8105
8106 os << "\tif (i.getOpcode() == TCE::TCEBRNEri) {" << std::endl
8107 << "\t\tcond.push_back(i.getOperand(0));" << std::endl
8108 << "\t\tcond.push_back(i.getOperand(1));" << std::endl
8109 << "\t\tcond.push_back(MachineOperand::CreateImm(103));"
8110 << std::endl
8111 << "\t\treturn false;" << std::endl
8112 << "\t}" << std::endl;
8113 }
8114
8115 if (opNames_.count("TCEBRGTrr")) {
8116 os << "\tif (i.getOpcode() == TCE::TCEBRGTrr) {" << std::endl
8117 << "\t\tcond.push_back(i.getOperand(0));" << std::endl
8118 << "\t\tcond.push_back(i.getOperand(1));" << std::endl
8119 << "\t\tcond.push_back(MachineOperand::CreateImm(4));"
8120 << std::endl
8121 << "\t\treturn false;" << std::endl
8122 << "\t}" << std::endl;
8123
8124 os << "\tif (i.getOpcode() == TCE::TCEBRGTri) {" << std::endl
8125 << "\t\tcond.push_back(i.getOperand(0));" << std::endl
8126 << "\t\tcond.push_back(i.getOperand(1));" << std::endl
8127 << "\t\tcond.push_back(MachineOperand::CreateImm(104));"
8128 << std::endl
8129 << "\t\treturn false;" << std::endl
8130 << "\t}" << std::endl;
8131 }
8132
8133 if (opNames_.count("TCEBRGTUrr")) {
8134 os << "\tif (i.getOpcode() == TCE::TCEBRGTUrr) {" << std::endl
8135 << "\t\tcond.push_back(i.getOperand(0));" << std::endl
8136 << "\t\tcond.push_back(i.getOperand(1));" << std::endl
8137 << "\t\tcond.push_back(MachineOperand::CreateImm(6));"
8138 << std::endl
8139 << "\t\treturn false;" << std::endl
8140 << "\t}" << std::endl;
8141
8142 os << "\tif (i.getOpcode() == TCE::TCEBRGTUri) {" << std::endl
8143 << "\t\tcond.push_back(i.getOperand(0));" << std::endl
8144 << "\t\tcond.push_back(i.getOperand(1));" << std::endl
8145 << "\t\tcond.push_back(MachineOperand::CreateImm(106));"
8146 << std::endl
8147 << "\t\treturn false;" << std::endl
8148 << "\t}" << std::endl;
8149 }
8150
8151 if (opNames_.count("TCEBRLTrr")) {
8152 os << "\tif (i.getOpcode() == TCE::TCEBRLTrr) {" << std::endl
8153 << "\t\tcond.push_back(i.getOperand(0));" << std::endl
8154 << "\t\tcond.push_back(i.getOperand(1));" << std::endl
8155 << "\t\tcond.push_back(MachineOperand::CreateImm(14));"
8156 << std::endl
8157 << "\t\treturn false;" << std::endl
8158 << "\t}" << std::endl;
8159
8160 os << "\tif (i.getOpcode() == TCE::TCEBRLTri) {" << std::endl
8161 << "\t\tcond.push_back(i.getOperand(0));" << std::endl
8162 << "\t\tcond.push_back(i.getOperand(1));" << std::endl
8163 << "\t\tcond.push_back(MachineOperand::CreateImm(114));"
8164 << std::endl
8165 << "\t\treturn false;" << std::endl
8166 << "\t}" << std::endl;
8167 }
8168
8169 if (opNames_.count("TCEBRLTUrr")) {
8170 os << "\tif (i.getOpcode() == TCE::TCEBRLTUrr) {" << std::endl
8171 << "\t\tcond.push_back(i.getOperand(0));" << std::endl
8172 << "\t\tcond.push_back(i.getOperand(1));" << std::endl
8173 << "\t\tcond.push_back(MachineOperand::CreateImm(15));"
8174 << std::endl
8175 << "\t\treturn false;" << std::endl
8176 << "\t}" << std::endl;
8177
8178 os << "\tif (i.getOpcode() == TCE::TCEBRLTUri) {" << std::endl
8179 << "\t\tcond.push_back(i.getOperand(0));" << std::endl
8180 << "\t\tcond.push_back(i.getOperand(1));" << std::endl
8181 << "\t\tcond.push_back(MachineOperand::CreateImm(115));"
8182 << std::endl
8183 << "\t\treturn false;" << std::endl
8184 << "\t}" << std::endl;
8185 }
8186
8187 if (opNames_.count("TCEBRLErr")) {
8188 os << "\tif (i.getOpcode() == TCE::TCEBRLErr) {" << std::endl
8189 << "\t\tcond.push_back(i.getOperand(0));" << std::endl
8190 << "\t\tcond.push_back(i.getOperand(1));" << std::endl
8191 << "\t\tcond.push_back(MachineOperand::CreateImm(5));"
8192 << std::endl
8193 << "\t\treturn false;" << std::endl
8194 << "\t}" << std::endl;
8195
8196 os << "\tif (i.getOpcode() == TCE::TCEBRLEri) {" << std::endl
8197 << "\t\tcond.push_back(i.getOperand(0));" << std::endl
8198 << "\t\tcond.push_back(i.getOperand(1));" << std::endl
8199 << "\t\tcond.push_back(MachineOperand::CreateImm(105));"
8200 << std::endl
8201 << "\t\treturn false;" << std::endl
8202 << "\t}" << std::endl;
8203 }
8204
8205 if (opNames_.count("TCEBRLEUrr")) {
8206 os << "\tif (i.getOpcode() == TCE::TCEBRLEUrr) {" << std::endl
8207 << "\t\tcond.push_back(i.getOperand(0));" << std::endl
8208 << "\t\tcond.push_back(i.getOperand(1));" << std::endl
8209 << "\t\tcond.push_back(MachineOperand::CreateImm(7));"
8210 << std::endl
8211 << "\t\treturn false;" << std::endl
8212 << "\t}" << std::endl;
8213
8214 os << "\tif (i.getOpcode() == TCE::TCEBRLEUri) {" << std::endl
8215 << "\t\tcond.push_back(i.getOperand(0));" << std::endl
8216 << "\t\tcond.push_back(i.getOperand(1));" << std::endl
8217 << "\t\tcond.push_back(MachineOperand::CreateImm(107));"
8218 << std::endl
8219 << "\t\treturn false;" << std::endl
8220 << "\t}" << std::endl;
8221 }
8222
8223 if (opNames_.count("TCEBRGErr")) {
8224 os << "\tif (i.getOpcode() == TCE::TCEBRGErr) {" << std::endl
8225 << "\t\tcond.push_back(i.getOperand(0));" << std::endl
8226 << "\t\tcond.push_back(i.getOperand(1));" << std::endl
8227 << "\t\tcond.push_back(MachineOperand::CreateImm(16));"
8228 << std::endl
8229 << "\t\treturn false;" << std::endl
8230 << "\t}" << std::endl;
8231
8232 os << "\tif (i.getOpcode() == TCE::TCEBRGEri) {" << std::endl
8233 << "\t\tcond.push_back(i.getOperand(0));" << std::endl
8234 << "\t\tcond.push_back(i.getOperand(1));" << std::endl
8235 << "\t\tcond.push_back(MachineOperand::CreateImm(116));"
8236 << std::endl
8237 << "\t\treturn false;" << std::endl
8238 << "\t}" << std::endl;
8239 }
8240
8241 if (opNames_.count("TCEBRGEUrr")) {
8242 os << "\tif (i.getOpcode() == TCE::TCEBRGEUrr) {" << std::endl
8243 << "\t\tcond.push_back(i.getOperand(0));" << std::endl
8244 << "\t\tcond.push_back(i.getOperand(1));" << std::endl
8245 << "\t\tcond.push_back(MachineOperand::CreateImm(17));"
8246 << std::endl
8247 << "\t\treturn false;" << std::endl
8248 << "\t}" << std::endl;
8249
8250 os << "\tif (i.getOpcode() == TCE::TCEBRGEUri) {" << std::endl
8251 << "\t\tcond.push_back(i.getOperand(0));" << std::endl
8252 << "\t\tcond.push_back(i.getOperand(1));" << std::endl
8253 << "\t\tcond.push_back(MachineOperand::CreateImm(117));"
8254 << std::endl
8255 << "\t\treturn false;" << std::endl
8256 << "\t}" << std::endl;
8257 }
8258 }
8259 os << "\treturn true;"
8260 << "}" << std::endl << std::endl;
8261
8262 // insert branch
8263
8264 os << "#include <llvm/CodeGen/MachineInstrBuilder.h>" << std::endl
8265 << std::endl;
8266
8267 os << "void TCEInstrInfo::insertCCBranch( " << std::endl
8268 << "\tMachineBasicBlock& mbb," << std::endl
8269 << "\tMachineBasicBlock& tbb," << std::endl
8270 << "\tArrayRef<MachineOperand> cond," << std::endl
8271 << "const DebugLoc& dl) const {" << std::endl
8272 << "\tassert(cond.size() == 3);" << std::endl;
8273
8274 os << "\tint opcode;" << std::endl;
8275
8278 os << "\tswitch (cond[2].getImm()) {" << std::endl
8279 << "\t\tcase 2: opcode = TCE::EQ_JUMP;break;" << std::endl
8280 << "\t\tcase 3: opcode = TCE::NE_JUMP;break;" << std::endl
8281 << "\t\tcase 4: opcode = TCE::GT_JUMP;break;" << std::endl
8282 << "\t\tcase 5: opcode = TCE::LE_JUMP;break;" << std::endl
8283 << "\t\tcase 6: opcode = TCE::GTU_JUMP;break;" << std::endl
8284 << "\t\tcase 7: opcode = TCE::LEU_JUMP;break;" << std::endl;
8285
8286 if (opNames_.find("EQF_JUMP") != opNames_.end()) {
8287 os << "\t\tcase 8: opcode = TCE::EQF_JUMP;break;" << std::endl;
8288 }
8289 if (opNames_.find("NEF_JUMP") != opNames_.end()) {
8290 os << "\t\tcase 9: opcode = TCE::NEF_JUMP;break;" << std::endl;
8291 }
8292 if (opNames_.find("LEF_JUMP") != opNames_.end()) {
8293 os << "\t\tcase 10: opcode = TCE::LEF_JUMP;break;" << std::endl;
8294 }
8295 if (opNames_.find("GEF_JUMP") != opNames_.end()) {
8296 os << "\t\tcase 11: opcode = TCE::GEF_JUMP;break;" << std::endl;
8297 }
8298 if (opNames_.find("LTF_JUMP") != opNames_.end()) {
8299 os << "\t\tcase 12: opcode = TCE::LTF_JUMP;break;" << std::endl;
8300 }
8301 if (opNames_.find("GEF_JUMP") != opNames_.end()) {
8302 os << "\t\tcase 13: opcode = TCE::GTF_JUMP;break;" << std::endl;
8303 }
8304
8305 os << "\t\tdefault: assert(false && \"Unknown condition code\");}"
8306 << std::endl;
8309 os << "\tswitch (cond[2].getImm()) {" << std::endl;
8310 if (opNames_.count("TCEBREQrr")) {
8311 os << "\t\tcase 2: opcode = TCE::TCEBREQrr; break;" << std::endl
8312 << "\t\tcase 102: opcode = TCE::TCEBREQri; break;"
8313 << std::endl;
8314 }
8315 if (opNames_.count("TCEBRNErr")) {
8316 os << "\t\tcase 3: opcode = TCE::TCEBRNErr; break;" << std::endl
8317 << "\t\tcase 103: opcode = TCE::TCEBRNEri; break;"
8318 << std::endl;
8319 }
8320 if (opNames_.count("TCEBRGTrr")) {
8321 os << "\t\tcase 4: opcode = TCE::TCEBRGTrr; break;" << std::endl
8322 << "\t\tcase 104: opcode = TCE::TCEBRGTri; break;"
8323 << std::endl;
8324 }
8325 if (opNames_.count("TCEBRGTUrr")) {
8326 os << "\t\tcase 6: opcode = TCE::TCEBRGTUrr; break;" << std::endl
8327 << "\t\tcase 106: opcode = TCE::TCEBRGTUri; break;"
8328 << std::endl;
8329 }
8330 if (opNames_.count("TCEBRLTrr")) {
8331 os << "\t\tcase 14: opcode = TCE::TCEBRLTrr; break;" << std::endl
8332 << "\t\tcase 114: opcode = TCE::TCEBRLTri; break;"
8333 << std::endl;
8334 }
8335 if (opNames_.count("TCEBRLTUrr")) {
8336 os << "\t\tcase 15: opcode = TCE::TCEBRLTUrr; break;" << std::endl
8337 << "\t\tcase 115: opcode = TCE::TCEBRLTUri; break;"
8338 << std::endl;
8339 }
8340 if (opNames_.count("TCEBRLErr")) {
8341 os << "\t\tcase 5: opcode = TCE::TCEBRLErr; break;" << std::endl
8342 << "\t\tcase 105: opcode = TCE::TCEBRLEri; break;"
8343 << std::endl;
8344 }
8345 if (opNames_.count("TCEBRLEUrr")) {
8346 os << "\t\tcase 7: opcode = TCE::TCEBRLEUrr; break;" << std::endl
8347 << "\t\tcase 107: opcode = TCE::TCEBRLEUri; break;"
8348 << std::endl;
8349 }
8350 if (opNames_.count("TCEBRGErr")) {
8351 os << "\t\tcase 16: opcode = TCE::TCEBRGErr; break;" << std::endl
8352 << "\t\tcase 116: opcode = TCE::TCEBRGEri; break;"
8353 << std::endl;
8354 }
8355 if (opNames_.count("TCEBRGEUrr")) {
8356 os << "\t\tcase 17: opcode = TCE::TCEBRGEUrr; break;" << std::endl
8357 << "\t\tcase 117: opcode = TCE::TCEBRGEUri; break;"
8358 << std::endl;
8359 }
8360 os << "\t\tdefault: assert(false && \"Unknown condition code\");}"
8361 << std::endl;
8362 } else {
8363 os << "\tassert(false && \"Unknown condition code\");" << std::endl;
8364 }
8365
8366 os << "\tif (cond[1].isReg()) {" << std::endl
8367 << "\t\tBuildMI(&mbb, dl, get(opcode)).addReg(cond[0].getReg())"
8368 << std::endl
8369 << "\t\t .addReg(cond[1].getReg()).addMBB(&tbb);" << std::endl
8370 << "\t} else {" << std::endl
8371 << "\t\tBuildMI(&mbb, dl, get(opcode)).addReg(cond[0].getReg())"
8372 << std::endl
8373 << "\t\t .addImm(cond[1].getImm()).addMBB(&tbb);" << std::endl
8374 << "\t}" << std::endl;
8375 os << "}";
8376}
8377
8378void TDGen::write64bitMoveDefs(std::ostream& o) {
8379 o << std::endl << "// 64-bit register->register move definitions."
8380 << std::endl << "let isAsCheapAsAMove = 1 in {" << std::endl;
8381
8382 o << "def MOV64rr : InstTCE<(outs R64Regs:$dst), (ins R64Regs:$src),"
8383 << " \"$src -> $dst;\", []>;" << std::endl;
8384
8385 o << "def PRED_TRUE_MOV64rr : InstTCE<(outs R64Regs:$dst), "
8386 << "(ins R1Regs:$pred, R64Regs:$src), \"$src -> $dst;\", []>;"
8387 << std::endl;
8388
8389 o << "def PRED_FALSE_MOV64rr : InstTCE<(outs R64Regs:$dst), "
8390 << "(ins R1Regs:$pred, R64Regs:$src), \"$src -> $dst;\", []>;"
8391 << std::endl;
8392
8393 o << "} // end of is as cheap as move" << std::endl;
8394}
8395
8397 o << std::endl
8398 << "#include <llvm/CodeGen/MachineInstrBuilder.h>" << std::endl
8399 << "// copies 64-bit reg to a another" << std::endl
8400 << "bool TCEInstrInfo::copyPhys64bitReg(" << std::endl
8401 << "\tMachineBasicBlock& mbb," << std::endl
8402 << "\tMachineBasicBlock::iterator mbbi," << std::endl
8403 << "const DebugLoc& dl," << std::endl
8404 << "\tunsigned destReg, unsigned srcReg," << std::endl
8405 << "\tbool killSrc) const {" << std::endl
8406 << std::endl;
8407
8408 if (mach_.is64bit()) {
8409 o << "\tif (TCE::R64RegsRegClass.contains(destReg, srcReg)) {\n"
8410 << "\t\tBuildMI(mbb, mbbi, dl, get(TCE::MOV64rr), destReg)\n"
8411 << "\t\t\t.addReg(srcReg, getKillRegState(killSrc));" << std::endl
8412 << "\t\treturn true;" << std::endl
8413 << "}" << std::endl;
8414 }
8415 o << "\treturn false;" << std::endl
8416 << "}";
8417}
8418
8419void TDGen::writeAddressingModeDefs(std::ostream& o) {
8420 if (!mach_.is64bit()) {
8421 o << std::endl
8422 << "// Addressing modes." << std::endl
8423 << "def ADDRrr : ComplexPattern<i32, 2, \"SelectADDRrr\", [], []>;" << std::endl
8424 << "def ADDRri : ComplexPattern<i32, 2, \"SelectADDRri\", [frameindex], []>;" << std::endl
8425 << std::endl
8426 << "// Address operands" << std::endl
8427 << "def MEMrr : Operand<i32> {" << std::endl
8428 << "let PrintMethod = \"printMemOperand\";" << std::endl
8429 << "let MIOperandInfo = (ops R32IRegs, R32IRegs);" << std::endl
8430 << "}" << std::endl
8431 << "def MEMri : Operand<i32> {" << std::endl
8432 << "let PrintMethod = \"printMemOperand\";" << std::endl
8433 << "let MIOperandInfo = (ops R32IRegs, i32imm);" << std::endl
8434 << "}" << std::endl
8435 << std::endl
8436 << "// Branch targets have OtherVT type." << std::endl
8437 << "def brtarget : Operand<OtherVT>; " << std::endl
8438 << "def calltarget : Operand<i32>;" << std::endl;
8439
8440 o << "def SDT_TCECall : SDTypeProfile<0, 1, [SDTCisVT<0, i32>]>;" << std::endl;
8441 } else {
8442 o << std::endl
8443 << "// Addressing modes." << std::endl
8444 << "def ADDRrr : ComplexPattern<i64, 2, \"SelectADDRrr\", [], []>;" << std::endl
8445 << "def ADDRri : ComplexPattern<i64, 2, \"SelectADDRri\", [frameindex], []>;" << std::endl
8446 << std::endl
8447 << "// Address operands" << std::endl
8448 << "def MEMrr : Operand<i64> {" << std::endl
8449 << "let PrintMethod = \"printMemOperand\";" << std::endl
8450 << "let MIOperandInfo = (ops R64IRegs, R64IRegs);" << std::endl
8451 << "}" << std::endl
8452 << "def MEMri : Operand<i64> {" << std::endl
8453 << "let PrintMethod = \"printMemOperand\";" << std::endl
8454 << "let MIOperandInfo = (ops R64IRegs, i64imm);" << std::endl
8455 << "}" << std::endl
8456 << std::endl
8457 << "// Branch targets have OtherVT type." << std::endl
8458 << "def brtarget : Operand<OtherVT>; " << std::endl
8459 << "def calltarget : Operand<i64>;" << std::endl;
8460
8461 o << "def SDT_TCECall : SDTypeProfile<0, 1, [SDTCisVT<0, i64>]>;" << std::endl;
8462 }
8463}
8464
8465void TDGen::writeMiscPatterns(std::ostream& o) {
8466 if (!mach_.is64bit()) {
8467 o << "// zero extending moves used in some patterns" << std::endl
8468 << "def ANDext : InstTCE<(outs R32IRegs:$dst), (ins R1Regs:$src, i32imm:$val), \"\", []>;" << std::endl
8469 << "def PRED_TRUE_ANDext : InstTCE<(outs R32IRegs:$dst),"
8470 << " (ins R1Regs:$pred, R1Regs:$src, i32imm:$val), \"\", []>;" << std::endl
8471 << "def PRED_FALSE_ANDext : InstTCE<(outs R32IRegs:$dst),"
8472 << " (ins R1Regs:$pred, R1Regs:$src, i32imm:$val),\"\", []>;" << std::endl
8473 << "def XORbicmp: InstTCE<(outs R1Regs:$dst),"
8474 << " (ins R1Regs:$src, i32imm:$val), \"\", []>;" << std::endl
8475 << "def PRED_TRUE_XORbicmp: InstTCE<(outs R1Regs:$dst),"
8476 << " (ins R1Regs:$pred, R1Regs:$src, i32imm:$val), \"\", []>;" << std::endl
8477 << "def PRED_FALSE_XORbicmp: InstTCE<(outs R1Regs:$dst),"
8478 << " (ins R1Regs:$pred, R1Regs:$src, i32imm:$val), \"\", []>;" << std::endl;
8479
8480 o << "def: Pat <(i32 (anyext R1Regs:$src)), (ANDext R1Regs:$src, 1)>;" << std::endl
8481 << "def: Pat <(i32 (zext R1Regs:$src)), (ANDext R1Regs:$src, 1)>;" << std::endl;
8482
8483 o << "// select of 1 or 0." << std::endl
8484 << "def : Pat<(i32 (select R1Regs:$c, (i32 1), (i32 0))),"
8485 << " (ANDext R1Regs:$c, 1)>;" << std::endl;
8486
8487 o << std::endl
8488 << "def: Pat <(i32 (sext R1Regs:$src)), (SUBrir 0,(ANDext R1Regs:$src, 1))>;"
8489 << std::endl;
8490
8491 o << "// ------ Shift (emulation) patterns. " << std::endl
8492 << "def: Pat <(i32 (shl R32IRegs:$val, (i32 1))),"
8493 << " (ADDrrr R32Regs:$val, R32Regs:$val)>;" << std::endl
8494 << "def: Pat <(i32 (TCESHLConst R32IRegs:$val, (i32 1))),"
8495 << " (ADDrrr R32IRegs:$val, R32IRegs:$val)>;" << std::endl;
8496
8497 o << "// ----- Global addresses, constant pool entries ------" << std::endl
8498 << "def TCEGlobalAddr : SDNode<\"TCEISD::GLOBAL_ADDR\", SDTIntUnaryOp>;" << std::endl
8499 << "def TCEConstPool : SDNode<\"TCEISD::CONST_POOL\", SDTIntUnaryOp>;" << std::endl
8500 << "def : Pat<(TCEGlobalAddr tglobaladdr:$in), (MOVI32ri tglobaladdr:$in)>;" << std::endl
8501 << "def : Pat<(TCEGlobalAddr tconstpool:$in), (MOVI32ri tconstpool:$in)>;" << std::endl
8502 << "def : Pat<(TCEConstPool tglobaladdr:$in), (MOVI32ri tglobaladdr:$in)>;" << std::endl
8503 << "def : Pat<(TCEConstPool tconstpool:$in), (MOVI32ri tconstpool:$in)>;" << std::endl;
8504
8505
8506 o << "// some peephole patterns." << std::endl
8507 << "// 1-bit select with imm values - xor or mov." << std::endl
8508 << "def : Pat<(i1 (select R1Regs:$c, (i1 0), (i1 -1))), (XORbbj R1Regs:$c, 1)>;" << std::endl
8509 << "def : Pat<(i1 (select R1Regs:$c, (i1 -1), (i1 0))), (MOVI1rr R1Regs:$c)>;" << std::endl
8510 << "def : Pat<(i1 (select R1Regs:$c, (i1 -1), R1Regs:$F)), (IORbbb R1Regs:$c, R1Regs:$F)>;" << std::endl
8511 << "def : Pat<(i1 (select R1Regs:$c, R1Regs:$T, (i1 0))), (ANDbbb R1Regs:$c, R1Regs:$T)>;" << std::endl;
8512
8513 o << "// 1-bit comparison between booleans - xor or xnor(implemented with 2 xors)" << std::endl
8514 << "def : Pat<(i1 (setne R1Regs:$op1, R1Regs:$op2)), (XORbbb R1Regs:$op1, R1Regs:$op2)>;" << std::endl
8515 << "// TODO: should the temp values be converted to i32? usually more i32 regs." << std::endl
8516 << "def : Pat<(i1 (seteq R1Regs:$op1, R1Regs:$op2)), (XORbbj (XORbbb R1Regs:$op1, R1Regs:$op2), 1)>;" << std::endl;
8517
8518 o << "def TCEBlockAddress : SDNode<\"TCEISD::BLOCK_ADDR\", SDTIntUnaryOp>;" << std::endl
8519 << "def : Pat<(TCEBlockAddress tblockaddress:$src1), (MOVI32ri tblockaddress:$src1)>;" << std::endl;
8520
8521 } else {
8522 o << "// zero extending moves used in some patterns" << std::endl
8523 << "def ANDext : InstTCE<(outs R64IRegs:$dst),"
8524 << " (ins R1Regs:$src, i64imm:$val), \"\", []>;" << std::endl
8525 << "def PRED_TRUE_ANDext : InstTCE<(outs R64IRegs:$dst),"
8526 << " (ins R1Regs:$pred, R1Regs:$src, i64imm:$val), \"\", []>;" << std::endl
8527 << "def PRED_FALSE_ANDext : InstTCE<(outs R64IRegs:$dst),"
8528 << " (ins R1Regs:$pred, R1Regs:$src, i64imm:$val),\"\", []>;" << std::endl
8529 << "def XORbicmp: InstTCE<(outs R1Regs:$dst),"
8530 << " (ins R1Regs:$src, i64imm:$val), \"\", []>;" << std::endl
8531 << "def PRED_TRUE_XORbicmp: InstTCE<(outs R1Regs:$dst),"
8532 << " (ins R1Regs:$pred, R1Regs:$src, i64imm:$val), \"\", []>;" << std::endl
8533 << "def PRED_FALSE_XORbicmp: InstTCE<(outs R1Regs:$dst),"
8534 << " (ins R1Regs:$pred, R1Regs:$src, i64imm:$val), \"\", []>;" << std::endl;
8535
8536 o << "def: Pat <(i64 (anyext R1Regs:$src)), (ANDext R1Regs:$src, 1)>;" << std::endl
8537 << "def: Pat <(i64 (zext R1Regs:$src)), (ANDext R1Regs:$src, 1)>;" << std::endl;
8538
8539 o << "// select of 1 or 0." << std::endl
8540 << "def : Pat<(i64 (select R1Regs:$c, (i64 1), (i64 0))), (ANDext R1Regs:$c, 1)>;" << std::endl;
8541
8542 o << std::endl
8543 << "def: Pat <(i64 (sext R1Regs:$src)), (SUB64sas 0,(ANDext R1Regs:$src, 1))>;"
8544 << std::endl;
8545
8546 o << "// ------ Shift (emulation) patterns. " << std::endl
8547 << "def: Pat <(i64 (shl R64IRegs:$val, (i64 1))),"
8548 << " (ADD64sss R64Regs:$val, R64Regs:$val)>;" << std::endl
8549 << "def: Pat <(i64 (TCESHLConst R64IRegs:$val, (i64 1))),"
8550 << " (ADD64sss R64IRegs:$val, R64IRegs:$val)>;" << std::endl;
8551
8552 o << "// ----- Global addresses, constant pool entries ------" << std::endl
8553 << "def TCEGlobalAddr : SDNode<\"TCEISD::GLOBAL_ADDR\", SDTIntUnaryOp>;" << std::endl
8554 << "def TCEConstPool : SDNode<\"TCEISD::CONST_POOL\", SDTIntUnaryOp>;" << std::endl
8555 << "def : Pat<(TCEGlobalAddr tglobaladdr:$in), (MOVI64sa tglobaladdr:$in)>;" << std::endl
8556 << "def : Pat<(TCEGlobalAddr tconstpool:$in), (MOVI64sa tconstpool:$in)>;" << std::endl
8557 << "def : Pat<(TCEConstPool tglobaladdr:$in), (MOVI64sa tglobaladdr:$in)>;" << std::endl
8558 << "def : Pat<(TCEConstPool tconstpool:$in), (MOVI64sa tconstpool:$in)>;" << std::endl;
8559
8560 o << "// some peephole patterns." << std::endl
8561 << "// 1-bit select with imm values - xor or mov." << std::endl
8562 << "def : Pat<(i1 (select R1Regs:$c, (i1 0), (i1 -1))), (XOR64bbj R1Regs:$c, 1)>;" << std::endl
8563 << "def : Pat<(i1 (select R1Regs:$c, (i1 -1), (i1 0))), (MOVI1rr R1Regs:$c)>;" << std::endl
8564 << "def : Pat<(i1 (select R1Regs:$c, (i1 -1), R1Regs:$F)), (IOR64bbb R1Regs:$c, R1Regs:$F)>;" << std::endl
8565 << "def : Pat<(i1 (select R1Regs:$c, R1Regs:$T, (i1 0))), (AND64bbb R1Regs:$c, R1Regs:$T)>;" << std::endl;
8566
8567 o << "// 1-bit comparison between booleans - xor or xnor(implemented with 2 xors)" << std::endl
8568 << "def : Pat<(i1 (setne R1Regs:$op1, R1Regs:$op2)), (XOR64bbb R1Regs:$op1, R1Regs:$op2)>;" << std::endl
8569 << "// TODO: should the temp values be converted to i64? usually more i64 regs." << std::endl
8570 << "def : Pat<(i1 (seteq R1Regs:$op1, R1Regs:$op2)), (XOR64bbj (XOR64bbb R1Regs:$op1, R1Regs:$op2), 1)>;" << std::endl;
8571
8572 o << "def TCEBlockAddress : SDNode<\"TCEISD::BLOCK_ADDR\", SDTIntUnaryOp>;" << std::endl
8573 << "def : Pat<(TCEBlockAddress tblockaddress:$src1), (MOVI64sa tblockaddress:$src1)>;" << std::endl;
8574 }
8575}
8576
8577void TDGen::writeConstShiftPat(std::ostream& os,
8578 const TCEString& nodeName,
8579 const TCEString& opNameBase, int i) {
8580
8581 if (!mach_.is64bit()) {
8582 TCEString opName = opNameBase; opName << i << "_32rr";
8583 if (opNames_.find(opName) != opNames_.end()) {
8584 os << "def : Pat<(i32 (" << nodeName
8585 << " R32IRegs:$val, (i32 " << i << "))), ("
8586 << opName << " R32IRegs:$val)>;" << std::endl;
8587 }
8588 } else {
8589 TCEString opName = opNameBase; opName << i << "_64rr";
8590 if (opNames_.find(opName) != opNames_.end()) {
8591 os << "def : Pat<(i64 (" << nodeName
8592 << " R64IRegs:$val, (i64 " << i << "))), ("
8593 << opName << " R64IRegs:$val)>;" << std::endl;
8594 }
8595 }
8596}
8597
8598
8599void TDGen::createConstShiftPatterns(std::ostream& os) {
8600 int bits = mach_.is64bit() ? 64: 32;
8601 for (int i = 1; i < bits; i++) {
8602 writeConstShiftPat(os, "TCESRAConst", "SHR", i);
8603 writeConstShiftPat(os, "TCESRLConst", "SHRU", i);
8604 writeConstShiftPat(os, "TCESHLConst", "SHL", i);
8605 }
8606}
8607
8609
8610 // TODO: what about true/false versions of these ops?
8611
8612 TCEString load = littleEndian_ ? "LD8" : "LDQ";
8613 TCEString uload = littleEndian_ ? "LDU8" : "LDQU";
8614 TCEString wload = littleEndian_ ?
8615 (mach_.is64bit() ? "LD64" : "LD32") : "LDW";
8616 if (mach_.hasOperation(load)) {
8617 os << "def " << load
8618 << "Br : InstTCE<(outs R1Regs:$op2), (ins MEMrr:$op1), \"\", "
8619 << "[(set R1Regs:$op2, (sextloadi1 ADDRrr:$op1))]>;" << std::endl
8620 << "def " << load
8621 << "Bi : InstTCE<(outs R1Regs:$op2), (ins MEMri:$op1), \"\", "
8622 << "[(set R1Regs:$op2, (sextloadi1 ADDRri:$op1))]>; " << std::endl;
8623
8624 opNames_[load + "Br"] = load;
8625 opNames_[load + "Bi"] = load;
8626
8627 }
8628 if (mach_.hasOperation(uload)) {
8629 os << "def " << uload
8630 << "Br : InstTCE<(outs R1Regs:$op2), (ins MEMrr:$op1), \"\", "
8631 << "[(set R1Regs:$op2, (zextloadi1 ADDRrr:$op1))]>;" << std::endl
8632 << "def " << uload
8633 << "Bi : InstTCE<(outs R1Regs:$op2), (ins MEMri:$op1), \"\", "
8634 << "[(set R1Regs:$op2, (zextloadi1 ADDRri:$op1))]>;" << std::endl;
8635 opNames_[uload + "Br"] = uload;
8636 opNames_[uload + "Bi"] = uload;
8637
8638 os << "def : Pat<(i1 (load ADDRrr:$addr)), ("
8639 << uload << "Br ADDRrr:$addr)>;" << std::endl;
8640 os << "def : Pat<(i1 (load ADDRri:$addr)), ("
8641 << uload << "Bi ADDRri:$addr)>;" << std::endl;
8642 } else {
8643 if (mach_.hasOperation(load)) {
8644 os << "def : Pat<(i1 (load ADDRrr:$addr)), ("
8645 << load << "Br ADDRrr:$addr)>;" << std::endl;
8646 os << "def : Pat<(i1 (load ADDRri:$addr)), ("
8647 << load << "Bi ADDRri:$addr)>;" << std::endl;
8648 }
8649 }
8650
8651 // if no 8-bit loads, create 32/64-bit loads for stack access but
8652 // no patterns for isel as only the stack is 32/64-bit aligned.
8653 // 1- and 8-bit loads on isel will be handled by lowering.
8654 if (!mach_.hasOperation(load) &&
8655 !mach_.hasOperation(uload) &&
8656 mach_.hasOperation(wload)) {
8657 os << "def " << wload
8658 << "Br : InstTCE<(outs R1Regs:$op2), (ins MEMrr:$op1), \"\", "
8659 << "[]>;" << std::endl
8660 << "def " << wload
8661 << "Bi : InstTCE<(outs R1Regs:$op2), (ins MEMri:$op1), \"\", "
8662 << "[]>;" << std::endl;
8663
8664 opNames_[wload + "Br"] = wload;
8665 opNames_[wload + "Bi"] = wload;
8666 }
8667
8668 TCEString halfLoad = littleEndian_ ? "LD16" : "LDH";
8669 if (!mach_.hasOperation(halfLoad)) {
8670 TCEString halfULoad = littleEndian_ ? "LDU16" : "LDHU";
8671 if (mach_.hasOperation(halfULoad)) {
8672 halfLoad = halfULoad;
8673 } else {
8674 return;
8675 }
8676 }
8677
8678 os << "def " << halfLoad << "hr : InstTCE<(outs HFPRegs:$op2), "
8679 << "(ins MEMrr:$op1), \"\", [(set HFPRegs:$op2, "
8680 << "(load ADDRrr:$op1))]>;" << std::endl;
8681
8682 os << "def " << halfLoad << "hi : InstTCE<(outs HFPRegs:$op2), "
8683 << "(ins MEMri:$op1), \"\", [(set HFPRegs:$op2, "
8684 << "(load ADDRri:$op1))]>;" << std::endl;
8685
8686 opNames_[halfLoad + "hr"] = halfLoad;
8687 opNames_[halfLoad + "hi"] = halfLoad;
8688
8689 // TODO: what about 32-bit?
8690}
8691
8692// ---------------------------------------------------------------------------
8693// ValueType implementation.
8694
8695/**
8696 * Constructor.
8697 *
8698 * @param subwWidth Subword width.
8699 * @param subwCount Subword count.
8700 * @param isFloat True, if is a floating point type.
8701 */
8702ValueType::ValueType(int subwWidth, int subwCount, bool isFloat)
8703 : subwWidth_(subwWidth), subwCount_(subwCount), isFloat_(isFloat) {
8704 assert(subwWidth > 0 && "Invalid value type.");
8705 assert(subwCount > 0 && "Invalid value type.");
8706}
8707
8708/**
8709 * Constructor.
8710 *
8711 * @param vtStr Value type string in LLVM format.
8712 */
8714 ValueType vt = valueType(vtStr);
8715 this->subwWidth_ = vt.subwWidth_;
8716 this->subwCount_ = vt.subwCount_;
8717 this->isFloat_ = vt.isFloat_;
8718}
8719
8720/**
8721 * Constructor.
8722 *
8723 * @param opnd Operand to be converted to ValueType.
8724 */
8726 ValueType vt = valueType(opnd);
8727 this->subwWidth_ = vt.subwWidth_;
8728 this->subwCount_ = vt.subwCount_;
8729 this->isFloat_ = vt.isFloat_;
8730}
8731
8732/**
8733 * Copy constructor.
8734 *
8735 * @param other Value to be copied.
8736 */
8738 : subwWidth_(other.subwWidth_),
8739 subwCount_(other.subwCount_),
8740 isFloat_(other.isFloat_) {}
8741
8742/**
8743 * Value assignment.
8744 *
8745 * @param other Value to be assigned.
8746 * @return Reference with the assigned values.
8747 */
8748ValueType&
8750 this->subwWidth_ = other.subwWidth_;
8751 this->subwCount_ = other.subwCount_;
8752 this->isFloat_ = other.isFloat_;
8753 return *this;
8754}
8755
8756/**
8757 * Tells whether ValueType is supported by LLVM or not.
8758 *
8759 * @return True, if ValueType is supported by LLVM.
8760 */
8761bool
8765 return true;
8766 }
8767 return false;
8768}
8769
8770/**
8771 * Returns ValueType's whole bitwidth.
8772 *
8773 * @return ValueType's whole bitwidth.
8774 */
8775int
8777 return subwWidth_ * subwCount_;
8778}
8779
8780/**
8781 * Returns ValueType's subword bitwidth.
8782 *
8783 * @return ValueType's subword bitwidth.
8784 */
8785int
8787 return subwWidth_;
8788}
8789
8790/**
8791 * Returns ValueType's subword count.
8792 *
8793 * @return ValueType's subword count.
8794 */
8795int
8797 return subwCount_;
8798}
8799
8800/**
8801 * Tells whether ValueType is a floating point type or not.
8802 *
8803 * @return True, is ValueType is a float type.
8804 */
8805bool
8807 return isFloat_;
8808}
8809
8810/**
8811 * Tells whether ValueType is a vector type or not.
8812 *
8813 * @return True, is ValueType is a vector type.
8814 */
8815bool
8817 return subwCount_ > 1;
8818}
8819
8820/**
8821 * Returns the Operand::OperandType of ValueType.
8822 *
8823 * @return OperandType of ValueType.
8824 */
8827 if (!isFloat_ && subwWidth_ == 1) {
8828 return Operand::BOOL;
8829 } else if (isFloat_ && subwWidth_ == 16) {
8831 } else if (isFloat_ && subwWidth_ == 32) {
8832 return Operand::FLOAT_WORD;
8833 } else if (!isFloat_) {
8834 return Operand::UINT_WORD;
8835 }
8836
8837 return Operand::UINT_WORD;
8838}
8839
8840/**
8841 * Returns ValueType in LLVM value type string format, e.g. "v2i32".
8842 *
8843 * @return Value type string in LLVM format.
8844 */
8847 const TCEString subwWidthStr = Conversion::toString(subwWidth_);
8848
8849 // Check if the value type is a scalar.
8850 if (subwCount_ == 1) {
8851 if (isFloat_) {
8852 return "f" + subwWidthStr;
8853 } else {
8854 return "i" + subwWidthStr;
8855 }
8856 }
8857
8858 // The value type is a vector.
8859 if (isFloat_) {
8860 return "v" + Conversion::toString(subwCount_) + "f" + subwWidthStr;
8861 } else {
8862 return "v" + Conversion::toString(subwCount_) + "i" + subwWidthStr;
8863 }
8864}
8865
8866/**
8867 * Returns Operand in LLVM value type string format, e.g. "v2i32".
8868 *
8869 * @param operand Operand that will be transformed to value type string.
8870 * @return Value type string in LLVM format.
8871 */
8874 if (operand.type() == Operand::FLOAT_WORD ||
8875 operand.type() == Operand::HALF_FLOAT_WORD) {
8876 ValueType vt(operand.elementWidth(), operand.elementCount(), true);
8877 return vt.valueTypeStr();
8878 } else {
8879 ValueType vt(operand.elementWidth(), operand.elementCount(), false);
8880 return vt.valueTypeStr();
8881 }
8882}
8883
8884/**
8885 * Returns given LLVM value type string (e.g. "v2i32") as ValueType.
8886 *
8887 * @param vtStr LLVM value type string to be converted to ValueType.
8888 * @return ValueType object of the LLVM value type string.
8889 */
8892 assert(vtStr.size() > 1);
8893
8894 // Check if the value type is a scalar.
8895 if (vtStr[0] != 'v') {
8896 int subwWidthStr = Conversion::toInt(vtStr.substr(1));
8897
8898 if (vtStr[0] == TDGen::OT_REG_FP) {
8899 return ValueType(subwWidthStr, 1, true);
8900 } else {
8901 return ValueType(subwWidthStr, 1, false);
8902 }
8903 }
8904
8905 // The value type is a vector, find float/integer type ("f"/"i")
8906 // indicator.
8907 size_t vtI = vtStr.length() - 1;
8908 while (vtI > 0 && std::isdigit(vtStr[vtI])) --vtI;
8909
8910 int subwCount = Conversion::toInt(vtStr.substr(1, vtI - 1));
8911 int subwWidth = Conversion::toInt(vtStr.substr(vtI + 1));
8912
8913 if (vtStr[vtI] == TDGen::OT_REG_FP) {
8914 return ValueType(subwWidth, subwCount, true);
8915 } else {
8916 return ValueType(subwWidth, subwCount, false);
8917 }
8918}
8919
8920/**
8921 * Returns given Operand as a value type object.
8922 *
8923 * @param operand Operand to be converted to ValueType.
8924 * @return ValueType presentation of the Operand.
8925 */
8928 return valueType(valueTypeStr(operand));
8929}
8930
8931/**
8932 * Returns a list of vector value types that match the given width.
8933 *
8934 * Currently filters out unsupported LLVM value types.
8935 *
8936 * @param width The width of the desired value types.
8937 * @param onlyInts If true, floating point types are not included to output.
8938 * @return Value types for given width in a container.
8939 */
8940std::vector<ValueType>
8941ValueType::vectorTypesOfWidth(int width, bool onlyInts) {
8942 std::vector<ValueType> vts;
8943
8944 int subwCount = 2;
8945 int subwWidth = width / subwCount;
8946
8947 while (subwWidth > 0) {
8948 ValueType intVt(subwWidth, subwCount, false);
8949 if (intVt.isSupportedByLLVM()) {
8950 vts.push_back(intVt);
8951 }
8952
8953 if (!onlyInts) {
8954 ValueType floatVt(subwWidth, subwCount, true);
8955 if (floatVt.isSupportedByLLVM()) {
8956 vts.push_back(floatVt);
8957 }
8958 }
8959
8960 subwWidth /= 2;
8961 subwCount *= 2;
8962 }
8963
8964 return vts;
8965}
8966
8967/**
8968 * Returns a list of vector value types that match the given subword width.
8969 *
8970 * Currently filters out unsupported LLVM value types.
8971 *
8972 * @param subwordWidth The subword width of the desired value types.
8973 * @param onlyInts If true, floating point types are not included to output.
8974 * @return Value types for given subword width in a container.
8975 */
8976std::vector<ValueType>
8977ValueType::vectorTypesOfSubwordWidth(int subwordWidth, bool onlyInts) {
8978 std::vector<ValueType> vts;
8979
8980 int subwCount = 2;
8981 int subwWidth = subwordWidth;
8982 int MAX_SUBW_COUNT = SIMD_WORD_WIDTH / BYTE_BITWIDTH;
8983
8984 while (subwWidth * subwCount <= SIMD_WORD_WIDTH &&
8985 subwCount <= MAX_SUBW_COUNT) {
8986 ValueType intVt(subwWidth, subwCount, false);
8987 if (intVt.isSupportedByLLVM()) {
8988 vts.push_back(intVt);
8989 }
8990
8991 if (!onlyInts) {
8992 ValueType floatVt(subwWidth, subwCount, true);
8993 if (floatVt.isSupportedByLLVM()) {
8994 vts.push_back(floatVt);
8995 }
8996 }
8997
8998 subwCount *= 2;
8999 }
9000
9001 return vts;
9002}
9003
9004// ---------------------------------------------------------------------------
9005// RegisterClass implementation.
9006
9007/**
9008 * Constructor.
9009 *
9010 * @param vt ValueType that is supported by the RegisterClass.
9011 * @param name Name of the RegisterClass.
9012 */
9014 : name_(name), vt_(vt), registers_(std::vector<RegisterInfo>()) {
9015 if (vt.width() < 8) {
9016 alignment_ = 8;
9017 } else {
9018 alignment_ = vt.width();
9019 }
9020}
9021
9022/**
9023 * Copy constructor.
9024 *
9025 * @param other RegisterClass to be copied.
9026 */
9028 : name_(other.name_),
9029 vt_(other.vt_),
9030 alignment_(other.alignment_),
9031 registers_(other.registers_) {}
9032
9033/**
9034 * Value assignment.
9035 *
9036 * @param other RegisterClass to be assigned.
9037 * @return Reference with the assigned values.
9038 */
9041 this->name_ = other.name_;
9042 this->vt_ = other.vt_;
9043 this->alignment_ = other.alignment_;
9044 this->registers_ = other.registers_;
9045 return *this;
9046}
9047
9048/**
9049 * Returns RegisterClass's name.
9050 *
9051 * @return Name of the RegisterClass.
9052 */
9055 return name_;
9056}
9057
9058/**
9059 * Returns the supported ValueType.
9060 *
9061 * @return Supported ValueType.
9062 */
9065 return vt_;
9066}
9067
9068/**
9069 * Returns the RegisterClass's alignment in bits.
9070 *
9071 * @return Alignment of RegisterClass in bits.
9072 */
9073int
9075 return alignment_;
9076}
9077
9078/**
9079 * Returns RegisterInfo pointed by the index.
9080 *
9081 * @return RegisterInfo pointed by the index.
9082 */
9085 assert(
9086 index >= static_cast<int>(0) &&
9087 index < static_cast<int>(registers_.size()));
9088 return registers_[index];
9089}
9090
9091/**
9092 * Returns how many registers is used by this RegisterClass.
9093 *
9094 * @return A number of registers used by this RegisterClass.
9095 */
9096size_t
9098 return registers_.size();
9099}
9100
9101/**
9102 * Sets the registers used by this RegisterClass.
9103 *
9104 * @param registers The new registers used by this RegisterClass.
9105 */
9106void
9107RegisterClass::addRegisters(const std::vector<RegisterInfo>& registers) {
9108 registers_.insert(registers_.end(), registers.begin(), registers.end());
9109}
#define __func__
#define abortWithError(message)
#define assert(condition)
const Byte BYTE_BITWIDTH
Definition BaseType.hh:136
#define sub
#define THROW_EXCEPTION(exceptionType, message)
Exception wrapper macro that automatically includes file name, line number and function name where th...
Definition Exception.hh:39
std::pair< std::string, int > ImmInfoKey
Definition ImmInfo.hh:53
find Finds info of the inner loops in the false
#define SIMD_WORD_WIDTH
Definition SimValue.hh:42
#define SUBIMM
#define ADDIMM
bool numbersToAscending(const TCEString &lhs, const TCEString &rhs)
Definition TDGen.cc:292
static const unsigned REG_RENAMER_PART
Definition TDGen.cc:332
char regOperandCharToImmOperandChar(char c)
Definition TDGen.cc:4491
static const int VERBOSE_LEVEL_DEFAULT
Default verbose level - do not print anything unnecessary.
static int verboseLevel()
static std::ostream & logStream()
static bool containsKey(const ContainerType &aContainer, const KeyType &aKey)
virtual Node & headNode(const Edge &edge) const
int nodeCount() const
virtual NodeSet rootNodes() const
useful utility functions
virtual Edge & outEdge(const Node &node, const int index) const
virtual Edge & inEdge(const Node &node, const int index) const
virtual void addNode(Node &node)
Node & node(const int index) const
virtual int inDegree(const Node &node) const
virtual NodeSet predecessors(const Node &node, bool ignoreBackEdges=false, bool ignoreForwardEdges=false) const
virtual int outDegree(const Node &node) const
virtual EdgeSet outEdges(const Node &node) const
virtual Node & tailNode(const Edge &edge) const
virtual void connectNodes(const Node &nTail, const Node &nHead, Edge &e)
virtual long value() const
static std::string toString(const T &source)
static int toInt(const T &source)
std::string errorMessage() const
Definition Exception.cc:123
std::set< GraphNode *, typename GraphNode::Comparator > NodeSet
Definition Graph.hh:53
bool canTakeImmediate(const Operation &operation, int inputOperandId, int64_t value, int destWidth)
Definition ImmInfo.cc:252
static ImmInfoKey key(const Operation &operation, int inputOperandId)
Definition ImmInfo.cc:57
bool canTakeImmediateByWidth(const Operation &operation, int inputOperandId, int bitWidth)
Definition ImmInfo.cc:275
std::pair< int64_t, int64_t > immediateValueBounds(const ImmInfoKey &key, int destWidth) const
Definition ImmInfo.cc:219
size_t count(const ImmInfoKey &key) const
Definition ImmInfo.hh:87
static ImmInfo * analyze(const TTAMachine::Machine &mach)
static OperationDAGSelector::OperationSet llvmRequiredOpset(bool includeFloatOps, bool isLittleEndian, bool bits64)
static std::set< const TTAMachine::RegisterFile *, TTAMachine::MachinePart::Comparator > tempRegisterFiles(const TTAMachine::Machine &machine)
static bool hasConditionalMoves(const TTAMachine::Machine &mach, const std::set< int > &rfWidths)
static bool supportsPortGuardedJump(const TTAMachine::Machine &machine, bool inverted, const TCEString &opName)
static bool supportsPortGuardedJumps(const TTAMachine::Machine &machine)
static OperationSet getOpset(const TTAMachine::Machine &mach)
static bool supportsBoolRegisterGuardedJumps(const TTAMachine::Machine &machine)
static Operation & osalOperation(const TTAMachine::HWOperation &hwOp)
static NullOperation & instance()
virtual bool isVector() const
Definition Operand.cc:268
virtual int elementCount() const
Definition Operand.cc:298
virtual bool isAddress() const
Definition Operand.cc:328
virtual void setElementWidth(int elementWidth)
Definition Operand.cc:288
virtual bool isInput() const
Definition Operand.cc:145
virtual bool isOutput() const
Definition Operand.cc:155
virtual int index() const
Definition Operand.cc:135
virtual void setType(OperandType type)
Definition Operand.cc:175
virtual const std::set< int > & swap() const
Definition Operand.cc:361
static int defaultElementWidth(OperandType type)
Definition Operand.cc:557
virtual int width() const
Definition Operand.cc:318
virtual OperandType type() const
Definition Operand.cc:165
virtual void setElementCount(int elementCount)
Definition Operand.cc:308
OperandType
Definition Operand.hh:58
@ 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
@ HALF_FLOAT_WORD
Definition Operand.hh:63
virtual int elementWidth() const
Definition Operand.cc:278
TCETools::CIStringSet OperationSet
static OperationDAGList findDags(const std::string &opName, OperationSet opSet, const ImmInfo *immInfo=nullptr)
const OperationDAG::NodeSet & endNodes() const
Operation & referencedOperation() const
Operation & operation(const char *name)
virtual bool isVectorOperation() const
Definition Operation.cc:222
virtual bool readsMemory() const
Definition Operation.cc:242
virtual OperationDAG & dag(int index) const
Definition Operation.cc:148
virtual TCEString name() const
Definition Operation.cc:93
virtual TCEString dagError(int index) const
Definition Operation.cc:182
virtual TCEString dagCode(int index) const
Definition Operation.cc:159
virtual Operand & output(int index) const
Definition Operation.cc:526
virtual Operand & input(int index) const
Definition Operation.cc:503
virtual int operandCount() const
Definition Operation.cc:212
OperationPimpl & impl()
Definition Operation.hh:170
virtual bool writesMemory() const
Definition Operation.cc:252
virtual int numberOfInputs() const
Definition Operation.cc:192
virtual bool canSwap(int id1, int id2) const
Definition Operation.cc:470
virtual int dagCount() const
Definition Operation.cc:134
virtual int numberOfOutputs() const
Definition Operation.cc:202
virtual Operand & operand(int id) const
Definition Operation.cc:541
static std::string stringToUpper(const std::string &source)
static std::string stringToLower(const std::string &source)
TCEString upper() const
Definition TCEString.cc:86
void write32bitRegisterInfo(std::ostream &o)
Definition TDGen.cc:1021
void write64bitMoveDefs(std::ostream &o)
Definition TDGen.cc:8378
static const char OT_VREG_INT32
Definition TDGen.hh:511
static const char OT_REG_LONG
Definition TDGen.hh:499
virtual TCEString llvmOperationName(const TCEString &opName) const
Definition TDGen.cc:5109
void writeInstrFormats(std::ostream &o)
Definition TDGen.cc:4255
std::map< TCEString, TCEString > shlOperations_
Contains machine's shl instructions (<ValueType, InstrName>).
Definition TDGen.hh:581
void writeVectorLoadStoreOperationExploitations(std::ostream &o)
Definition TDGen.cc:2704
std::string operandDefs_
Definition TDGen.hh:471
static const int MAX_SUBW_COUNT
Maximum number of subwords that any SIMD operation can have.
Definition TDGen.hh:488
void genTCETargetLoweringSIMD_addVectorRegisterClasses(std::ostream &o) const
Definition TDGen.cc:3053
std::vector< std::string > argRegNames_
Definition TDGen.hh:605
std::string subPattern(const Operation &op, const OperationDAG &dag)
Definition TDGen.cc:5468
static std::vector< std::string > supportedStackAccessOperations(const TTAMachine::Machine &mach)
Definition TDGen.cc:7685
std::string operationNodeToString(const Operation &op, const OperationDAG &dag, const OperationNode &node, bool emulationPattern, const std::string &operandTypes)
Definition TDGen.cc:5785
void writeVectorBitwiseOperationDefs(std::ostream &o, Operation &op, bool skipPattern)
Definition TDGen.cc:2657
std::vector< std::pair< const Operation *, TCEString > > truncOperations_
Contains machine's TRUNCxx/CFH instructions (<ValueType, InstrName>).
Definition TDGen.hh:551
void writeVectorOperationDef(std::ostream &o, Operation &op, TCEString valueTypes, const TCEString &attributes, bool skipPattern)
Definition TDGen.cc:2181
virtual void createSelectPatterns(std::ostream &os)
Definition TDGen.cc:7065
std::string immediateOperandNameForEmulatedOperation(const OperationDAG &, const Operand &operand)
Definition TDGen.cc:7584
bool writePortGuardedJumpDefPair(std::ostream &os, const TCEString &tceop1, const TCEString &tceop2, bool fp=false)
Definition TDGen.cc:3897
void writeVectorRegisterNames(std::ostream &o)
Definition TDGen.cc:2070
std::map< TCEString, Operation * > scalarOps_
Contains all scalar operations (<Name, Operation>).
Definition TDGen.hh:523
virtual std::string generateBackend() const
Definition TDGen.cc:486
virtual ~TDGen()
Definition TDGen.cc:383
bool canBeImmediate(const OperationDAG &dag, const TerminalNode &node)
Definition TDGen.cc:6123
std::string dagNodeToString(const Operation &op, const OperationDAG &dag, const OperationDAGNode &node, bool emulationPattern, const std::string &operandTypes, const Operation *emulatingOp=nullptr, const OperationDAGNode *successor=nullptr)
Definition TDGen.cc:5506
void associateRegistersWithVectorRegisterClasses()
Definition TDGen.cc:1709
bool hasConditionalMoves_
Definition TDGen.hh:623
bool isVectorStoreOperation(const Operation &op) const
Definition TDGen.cc:1977
void genGeneratedTCEPlugin_getVectorImmediateOpcode(std::ostream &o) const
Definition TDGen.cc:3235
const std::vector< OperationDAG * > getMatchableOperationDAGs(const Operation &op)
Definition TDGen.cc:5391
bool isWrongEndianessVectorOp(const Operation &op) const
Definition TDGen.cc:1983
void writeGuardRegisterClassInfo(std::ostream &o)
Definition TDGen.cc:2008
void writeHWLoopDef(std::ostream &o)
Definition TDGen.cc:3627
OperationDAG * createTrivialDAG(Operation &op)
Definition TDGen.cc:6093
static const char OT_VREG_INT16
Definition TDGen.hh:510
static const char OT_REG_BOOL
Definition TDGen.hh:497
void genGeneratedTCEPlugin_getStore(std::ostream &o) const
Definition TDGen.cc:2839
void genGeneratedTCEPlugin_getShlOpcode(std::ostream &o) const
Definition TDGen.cc:3300
bool use64bitForFP_
Definition TDGen.hh:633
std::vector< RegInfo > regs32bit_
Definition TDGen.hh:595
void writeAddressingModeDefs(std::ostream &o)
Definition TDGen.cc:8419
void genTCETargetLoweringSIMD_associatedVectorRegClass(std::ostream &o) const
Definition TDGen.cc:3098
std::vector< std::string > constantMaterializationPredicates_
All predicates used in constant materialization patterns.
Definition TDGen.hh:649
void writeArgRegsArray(std::ostream &os)
Definition TDGen.cc:6996
std::string argRegsArray_
Definition TDGen.hh:475
void analyzeRegisters()
Definition TDGen.cc:838
std::string createDefaultOperandTypeString(const Operation &op)
Definition TDGen.cc:5439
void writeOperationDef(std::ostream &o, Operation &op, const std::string &operandTypes, const std::string &attrs, bool skipPattern, std::string backendPrefix="")
Definition TDGen.cc:4649
static const int MAX_SCALAR_WIDTH
Distincts wide vs scalar registers.
Definition TDGen.hh:486
void verbose(const TCEString &msg) const
Definition TDGen.cc:1862
std::map< ImmInfoKey, std::string > immOperandDefs_
Maps (operation, operand) pairs to i32 immediate operand definition names.
Definition TDGen.hh:436
const TTAMachine::Machine & mach_
Definition TDGen.hh:463
void writeBooleanStorePatterns(std::ostream &os)
Definition TDGen.cc:4568
void writeControlFlowInstrDefs(std::ostream &os)
Definition TDGen.cc:3616
std::string addressingModeDefs_
Definition TDGen.hh:470
static const bool EXPLOIT_BIGGER_REGISTERS
If set to true, smaller vector value types can be stored to larger register files,...
Definition TDGen.hh:493
std::string operandTypesToRegisters(const std::string &opdTypes) const
Definition TDGen.cc:7885
static const char OT_IMM_LONG
Definition TDGen.hh:507
virtual TCEString llvmOperationPattern(const Operation &op, char operandType=' ') const
Definition TDGen.cc:4895
std::map< TCEString, TCEString > iorOperations_
Contains machine's shl instructions (<ValueType, InstrName>).
Definition TDGen.hh:583
virtual void writeCallDefRegs(std::ostream &o)
Definition TDGen.cc:3580
std::map< std::string, std::string > falsePredOps_
Definition TDGen.hh:612
int maxVectorSize_
Definition TDGen.hh:614
std::map< TCEString, TCEString > vbcastOperations_
Contains machine's VBCAST instructions (<ValueType, InstrName>).
Definition TDGen.hh:549
std::set< TCEString > movOperations_
Contains all moves between register classes (<InstrName>).
Definition TDGen.hh:586
std::map< TCEString, TDGenerator::RegisterClass > vRegClasses_
Contains required vector register classes (<ValueType, RegClass>).
Definition TDGen.hh:535
virtual void writeImmediateDef(std::ostream &o, const std::string &defName, const std::string &operandType, const std::string &predicate)
Definition TDGen.cc:4610
bool operationDAGCanBeMatched(const OperationDAG &op, std::set< std::string > *recursionCycleCheck=NULL, bool recursionHasStore=false)
Definition TDGen.cc:5315
RegClassMap regsInClasses_
All registers in certain group.
Definition TDGen.hh:645
static const char OT_VREG_FP
Definition TDGen.hh:512
bool hasRawOperands(const Operation &op) const
Definition TDGen.cc:1755
std::vector< RegInfo > regs64bit_
Definition TDGen.hh:597
bool canBePredicated(Operation &op, const std::string &operandTypes)
Definition TDGen.cc:7665
std::vector< std::string > llvmGuardRegs_
The LLVM register defs used as guards.
Definition TDGen.hh:599
std::map< std::string, std::string > truePredOps_
Definition TDGen.hh:611
void writeIntegerImmediateDefs(std::ostream &o, const ImmInfo &iivis)
Definition TDGen.cc:649
void createMinMaxDef(const TCEString &opName, const TCEString &valueName, std::ostream &os)
Definition TDGen.cc:6370
unsigned dregNum_
Definition TDGen.hh:468
ImmInfo * immInfo_
Definition TDGen.hh:465
void createConstantMaterializationQuery(std::ostream &os)
Definition TDGen.cc:6501
bool isVectorLoadOperation(const Operation &op) const
Definition TDGen.cc:1965
static const char OT_REG_FP
Definition TDGen.hh:500
std::string patOutputs(const Operation &op, const std::string &oprTypes)
Definition TDGen.cc:6074
unsigned int requiredI64Regs_
Definition TDGen.hh:631
void writeScalarToVectorDefs(std::ostream &o) const
Definition TDGen.cc:2388
void writeRegisterDef(std::ostream &o, const RegInfo &reg, const std::string regName, const std::string regTemplate, const std::string aliases, RegType type)
Definition TDGen.cc:503
virtual char operandChar(Operand &operand)
Definition TDGen.cc:4755
void analyzeMachineRegisters()
Definition TDGen.cc:1478
bool isVectorBitwiseOperation(const Operation &op) const
Definition TDGen.cc:1995
static const int BOOL_SUBW_WIDTH
Bool type subword width.
Definition TDGen.hh:484
static const char OT_VREG_BOOL
Definition TDGen.hh:508
void generateLoadStoreCopyGenerator(std::ostream &os)
Definition TDGen.cc:6365
TCEString associatedVectorRegisterClass(const Operand &operand) const
Definition TDGen.cc:1842
void writeCallingConvLicenceText(std::ostream &os)
Definition TDGen.cc:6975
void writeWiderVectorOperationExploitations(std::ostream &o)
Definition TDGen.cc:2831
void writeInstrDef(std::ostream &o, const std::string &instrDefName, const std::string &outs, const std::string &ins, const std::string &asmString, const std::string &pattern)
Definition TDGen.cc:4626
std::set< const TTAMachine::RegisterFile *, TTAMachine::MachinePart::Comparator > tempRegFiles_
Register files whose last reg reserved for temp reg copies.
Definition TDGen.hh:641
virtual void createMinMaxGenerator(std::ostream &os)
Definition TDGen.cc:6398
TCEString getLLVMPatternWithConstants(const Operation &op, const std::string &operandTypes, const std::string &operand0, const std::string &operand1) const
Definition TDGen.cc:7756
std::string tceOperationPattern(const Operation &op)
Definition TDGen.cc:5266
static const char OT_IMM_INT
Definition TDGen.hh:504
std::map< int, TCEString > baseClasses_
Contains vector base classes for register files (<Width, Name>).
Definition TDGen.hh:529
void writeConstShiftPat(std::ostream &os, const TCEString &nodeName, const TCEString &opNameBase, int i)
Definition TDGen.cc:8577
static const char OT_VREG_HFP
Definition TDGen.hh:513
int subwordWidthOfRawData(const Operation &op) const
Definition TDGen.cc:1778
std::string constantNodeString(const Operation &op, const OperationDAG &dag, const ConstantNode &node, const std::string &operandTypes, const OperationDAGNode *successor=nullptr)
Definition TDGen.cc:5611
static const int FP_SUBW_WIDTH
Float type subword width.
Definition TDGen.hh:480
static const char OT_REG_HFP
Definition TDGen.hh:501
void writeOperandDefs(std::ostream &o)
Definition TDGen.cc:621
void writePatternReplacement(std::ostream &o, const TCEString &origPat, const TCEString &replacerPat) const
Definition TDGen.cc:1875
static const char OT_IMM_FP
Definition TDGen.hh:505
void writeCallDef(std::ostream &o)
Definition TDGen.cc:3955
std::string instrInfo_
Definition TDGen.hh:472
void writeCallSeqStart(std::ostream &os)
Definition TDGen.cc:7944
void writeTopLevelTD(std::ostream &o)
Definition TDGen.cc:4231
std::map< int, std::vector< TDGenerator::RegisterInfo > > registers_
Contains registers fit for being vector registers (<Width, Registers>).
Definition TDGen.hh:532
unsigned int argRegCount_
Definition TDGen.hh:628
std::map< TCEString, Operation * > vectorOps_
Contains all vector operations (<Name, Operation>).
Definition TDGen.hh:526
void genGeneratedTCEPlugin_getGatherOpcode(std::ostream &o) const
Definition TDGen.cc:3255
void createByteExtLoadPatterns(std::ostream &os)
Definition TDGen.cc:6531
void writeVectorImmediateWriteDefs(std::ostream &instrInfoTD)
Definition TDGen.cc:3216
void writeVectorMemoryOperationDefs(std::ostream &o, Operation &op, bool skipPattern)
Definition TDGen.cc:2261
bool hasSelect_
Definition TDGen.hh:621
void initializeBackendContents()
Definition TDGen.cc:394
std::map< TCEString, TCEString > gatherOperations_
Contains machine's GATHER instructions (<ValueType, InstrName>).
Definition TDGen.hh:577
void writeRARegisterInfo(std::ostream &o)
Definition TDGen.cc:3157
void writeRegisterClasses(std::ostream &o)
Definition TDGen.cc:816
bool operationCanBeMatched(const Operation &op, std::set< std::string > *recursionCycleCheck=NULL, bool recursionHasStore=false)
Definition TDGen.cc:5281
void genGeneratedTCEPlugin_getLoadOpcode(std::ostream &o) const
Definition TDGen.cc:3271
bool prebypassStackIndeces_
Definition TDGen.hh:632
void writeCallingConv(std::ostream &os)
Definition TDGen.cc:6870
std::set< RegInfo > guardedRegs_
List of register that are associated with a guard on a bus.
Definition TDGen.hh:636
void saveAdditionalVectorOperationInfo(const Operation &op, const TCEString &valueTypes, bool isRegisterOp)
Definition TDGen.cc:2246
virtual std::string operandToString(const Operand &operand, bool match, char operandType, const std::string &immDefName="")
Definition TDGen.cc:5870
std::map< std::string, std::string > opNames_
Definition TDGen.hh:609
char operandTypeToRegister(const char &opdType) const
Definition TDGen.cc:7894
virtual void createVectorRVDRegNums(std::ostream &os)
Definition TDGen.cc:7022
std::map< std::string, RegInfo > regs_
Map of generated llvm register names to physical register in the machine.
Definition TDGen.hh:603
static const char OT_IMM_BOOL
Definition TDGen.hh:503
static const std::map< TCEString, TCEString > OPERATION_PATTERNS_
Contains <BaseOpName, OpPattern> key-value pairs.
Definition TDGen.hh:517
void createEndiannesQuery(std::ostream &os)
Definition TDGen.cc:6487
void genTCEInstrInfoSIMD_copyPhysVectorReg(std::ostream &o) const
Definition TDGen.cc:3187
unsigned int requiredI32Regs_
Minimum number of 32 bit registers.
Definition TDGen.hh:630
virtual void createConstantMaterializationPatterns(std::ostream &os)
Definition TDGen.cc:7458
std::vector< RegInfo > regs8bit_
Definition TDGen.hh:591
std::string emulatingOpNodeLLVMName(const Operation &op, const OperationDAG &dag, const OperationNode &node, const std::string &operandTypes)
Definition TDGen.cc:5674
void writeVectorOperationDefs(std::ostream &o, Operation &op, bool skipPattern)
Definition TDGen.cc:2164
void writeBackendCode(std::ostream &o)
Definition TDGen.cc:3997
void writeVectorTruncStoreDefs(std::ostream &o) const
Definition TDGen.cc:2318
std::string operationPattern(const Operation &op, const OperationDAG &dag, const std::string &operandTypes)
Definition TDGen.cc:5421
bool areImmediateOperandsLegal(const Operation &operation, const std::string &operandTypes) const
Definition TDGen.cc:7617
bool littleEndian_
Definition TDGen.hh:627
std::map< TCEString, TDGenerator::InstructionInfo > immediateStores_
All immediate store operations (<ValueType, InstrInfo>).
Definition TDGen.hh:542
std::string instrFormats_
Definition TDGen.hh:473
void writeVectorRegisterMoveDefs(std::ostream &o)
Definition TDGen.cc:2270
void write1bitRegisterInfo(std::ostream &o)
Definition TDGen.cc:961
void createShortExtLoadPatterns(std::ostream &os)
Definition TDGen.cc:6691
void orderEqualWidthRegistersToRoundRobin()
Definition TDGen.cc:1674
RegClassMap regsInRFClasses_
Definition TDGen.hh:647
std::string backendCode_
Definition TDGen.hh:476
std::map< TCEString, TDGenerator::InstructionInfo > registerStores_
All register store operations (<ValueType, InstrInfo>).
Definition TDGen.hh:538
void writeVectorBitConversions(std::ostream &o) const
Definition TDGen.cc:2418
void writeInstrInfo(std::ostream &o)
Definition TDGen.cc:3384
void createParamDRegNums(std::ostream &os)
Definition TDGen.cc:7010
void writeOperationDefs(std::ostream &o, Operation &op, bool skipPattern)
Definition TDGen.cc:4312
bool checkRequiredRegisters()
Definition TDGen.cc:3336
void writeVectorRegisterClasses(std::ostream &o) const
Definition TDGen.cc:2102
void writeCondBranchDefs(std::ostream &os)
Definition TDGen.cc:3661
void writeScalarOperationExploitations(std::ostream &o)
Definition TDGen.cc:2475
std::map< TCEString, TCEString > addOperations_
Contains machine's add instructions (<ValueType, InstrName>).
Definition TDGen.hh:579
void genGeneratedTCEPlugin_getLoad(std::ostream &o) const
Definition TDGen.cc:2939
void genGeneratedTCEPlugin_getIorOpcode(std::ostream &o) const
Definition TDGen.cc:3315
std::string callingConv_
Definition TDGen.hh:474
std::vector< RegInfo > regs16bit_
Definition TDGen.hh:593
void writeMiscPatterns(std::ostream &o)
Definition TDGen.cc:8465
void gatherAllMachineOperations()
Definition TDGen.cc:997
std::string registerInfo_
Definition TDGen.hh:469
TCEString getMovePattern(const char &opdType, const std::string &inputPattern) const
Definition TDGen.cc:7909
void write16bitRegisterInfo(std::ostream &o)
Definition TDGen.cc:1211
std::string topLevelTD_
Definition TDGen.hh:477
static const char OT_REG_DOUBLE
Definition TDGen.hh:502
void createBoolAndHalfLoadPatterns(std::ostream &os)
Definition TDGen.cc:8608
void genTCERegisterInfo_setReservedVectorRegs(std::ostream &os) const
Definition TDGen.cc:4203
void create32BitExtLoadPatterns(std::ostream &os)
Definition TDGen.cc:6808
const OperationDAG * getMatchableOperationDAG(const Operation &op)
Definition TDGen.cc:5361
void write64bitRegisterInfo(std::ostream &o)
Definition TDGen.cc:1363
std::map< TCEString, TDGenerator::InstructionInfo > registerLoads_
All register load operations (<ValueType, InstrInfo>).
Definition TDGen.hh:540
OperationDAGSelector::OperationSet allOpNames_
Contains all operation names in upper case.
Definition TDGen.hh:520
bool writeRegisterInfo(std::ostream &o)
Definition TDGen.cc:551
std::vector< std::string > gprRegNames_
Definition TDGen.hh:607
void analyzeMachineVectorRegisterClasses()
Definition TDGen.cc:1282
void writeVectorRegisterBaseClasses(std::ostream &o) const
Definition TDGen.cc:2047
bool hasRegisterClassSupport(const Operation &op) const
Definition TDGen.cc:1805
void writeStartOfRegisterInfo(std::ostream &o)
Definition TDGen.cc:594
void writeGetPointerAdjustmentQuery(std::ostream &os) const
Definition TDGen.cc:7522
void writeEmulationPattern(std::ostream &o, const Operation &op, const OperationDAG &dag)
Definition TDGen.cc:4800
static const int HFP_SUBW_WIDTH
Half float type subword width.
Definition TDGen.hh:482
static const char OT_VREG_INT8
Definition TDGen.hh:509
void createGetMaxMemoryAlignment(std::ostream &os) const
Definition TDGen.cc:7048
TDGen(const TTAMachine::Machine &mach, bool initialize=true)
Definition TDGen.cc:341
void createBranchAnalysis(std::ostream &os)
Definition TDGen.cc:7970
void createVectorMinMaxDef(const TCEString &opName, int bits, char llvmTypeChar, const TCEString &postFix, std::ostream &os)
Definition TDGen.cc:6380
static const std::string guardRegTemplateName
Definition TDGen.hh:651
static const char OT_IMM_HFP
Definition TDGen.hh:506
std::string immediatePredicate(int64_t lowerBoundInclusive, uint64_t upperBoundInclusive)
Definition TDGen.cc:7560
void createConstShiftPatterns(std::ostream &os)
Definition TDGen.cc:8599
static const char OT_REG_INT
Definition TDGen.hh:498
void genTCEInstrInfo_copyPhys64bitReg(std::ostream &o) const
Definition TDGen.cc:8396
void writeMoveImmediateDefs(std::ostream &o)
Definition TDGen.cc:756
std::vector< RegInfo > regs1bit_
Definition TDGen.hh:589
void genGeneratedTCEPlugin_getAddOpcode(std::ostream &o) const
Definition TDGen.cc:3285
std::string patInputs(const Operation &op, const std::string &oprTypes)
Definition TDGen.cc:6043
int maxScalarWidth_
Definition TDGen.hh:625
RegType
Definition TDGen.hh:97
@ RESERVED
Definition TDGen.hh:99
@ ARGUMENT
Definition TDGen.hh:100
@ RESULT
Definition TDGen.hh:101
@ GPR
Definition TDGen.hh:98
void genTCETargetLoweringSIMD_getSetCCResultVT(std::ostream &o) const
Definition TDGen.cc:3128
void writeOperationDefUsingGivenOperandTypes(std::ostream &o, Operation &op, bool skipPattern, std::vector< TDGenerator::ValueType > inputs, std::vector< TDGenerator::ValueType > outputs, TCEString instrSuffix="")
Definition TDGen.cc:1896
std::vector< std::string > resRegNames_
Definition TDGen.hh:606
int alignment_
RegisterClass alignment in bits, at least 8.
Definition TDGen.hh:758
std::vector< RegisterInfo > registers_
Register file registers that this RegisterClass uses.
Definition TDGen.hh:760
TCEString name() const
Definition TDGen.cc:9054
ValueType valueType() const
Definition TDGen.cc:9064
RegisterClass & operator=(const RegisterClass &other)
Definition TDGen.cc:9040
std::vector< RegisterInfo > registers() const
RegisterInfo registerInfo(int index) const
Definition TDGen.cc:9084
RegisterClass(const ValueType &vt, const TCEString &name)
Definition TDGen.cc:9013
ValueType vt_
Value type that is supported by this RegisterClass, e.g. v4i32.
Definition TDGen.hh:756
size_t numberOfRegisters() const
Definition TDGen.cc:9097
void addRegisters(const std::vector< RegisterInfo > &registers)
Definition TDGen.cc:9107
TCEString name_
RegisterClass name.
Definition TDGen.hh:754
static std::vector< ValueType > vectorTypesOfWidth(int width, bool onlyInts=false)
Definition TDGen.cc:8941
bool isFloat() const
Definition TDGen.cc:8806
ValueType & operator=(const ValueType &other)
Definition TDGen.cc:8749
int subwordCount() const
Definition TDGen.cc:8796
int subwCount_
Subword count of the value type.
Definition TDGen.hh:725
bool isFloat_
If true, the value type is a floating point type.
Definition TDGen.hh:727
bool isSupportedByLLVM() const
Definition TDGen.cc:8762
bool isVector() const
Definition TDGen.cc:8816
static const std::set< TCEString > SUPPORTED_LLVM_VALUE_TYPES
Contains all supported LLVM value types (<ValueType>).
Definition TDGen.hh:730
ValueType(int subwWidth, int subwCount, bool isFloat)
Definition TDGen.cc:8702
static std::vector< ValueType > vectorTypesOfSubwordWidth(int subwordWidth, bool onlyInt=false)
Definition TDGen.cc:8977
TCEString valueTypeStr() const
Definition TDGen.cc:8846
Operand::OperandType operandType() const
Definition TDGen.cc:8826
static ValueType valueType(const TCEString &vtStr)
Definition TDGen.cc:8891
int subwWidth_
Subword width of the value type.
Definition TDGen.hh:723
int width() const
Definition TDGen.cc:8776
int subwordWidth() const
Definition TDGen.cc:8786
virtual int size() const
virtual int width() const
virtual RFPort * port(const std::string &name) const
Guard * guard(int index) const
Definition Bus.cc:456
int guardCount() const
Definition Bus.cc:441
virtual TCEString name() const
virtual HWOperation * operation(const std::string &name) const
virtual int operationCount() const
virtual bool hasOperation(const std::string &name) const
const std::string & name() const
ComponentType * item(int index) const
virtual RegisterFileNavigator registerFileNavigator() const
Definition Machine.cc:450
virtual FunctionUnitNavigator functionUnitNavigator() const
Definition Machine.cc:380
virtual InstructionTemplateNavigator instructionTemplateNavigator() const
Definition Machine.cc:428
bool hasOperation(const TCEString &opName) const
Definition Machine.cc:1042
virtual ImmediateUnitNavigator immediateUnitNavigator() const
Definition Machine.cc:416
virtual BusNavigator busNavigator() const
Definition Machine.cc:356
virtual ControlUnit * controlUnit() const
Definition Machine.cc:345
bool is64bit() const
Definition Machine.hh:260
virtual bool isInput() const
Definition Port.cc:298
virtual bool isOutput() const
Definition Port.cc:308
virtual bool isReserved() const
virtual bool zeroRegister() const
const RegisterFile * registerFile() const
virtual int portCount() const
Definition Unit.cc:135
virtual int operandIndex() const
unsigned idx
Definition TDGen.hh:113
std::string rf
Definition TDGen.hh:112
TCEString regFileName_
Name of the register file the register belongs to, e.g. "RF".
Definition TDGen.hh:671
TCEString regName_
Register name in GenRegisterInfo.td, e.g. "KLUDGE_REGISTER".
Definition TDGen.hh:669
unsigned regIndex_
Register index in the register file.
Definition TDGen.hh:673