OpenASIP 2.2
Loading...
Searching...
No Matches
LLVMBackend.cc
Go to the documentation of this file.
1/*
2 Copyright (c) 2002-2021 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 * @file LLVMBackend.cc
26 *
27 * TCE runtime retargeting compiler backend.
28 *
29 * @author Veli-Pekka Jääskeläinen 2008 (vjaaskel-no.spam-cs.tut.fi)
30 * @author Mikael Lepistö 2009 (mikael.lepisto-no.spam-tut.fi)
31 * @author Pekka Jääskeläinen 2009-2021
32 * @note rating: red
33 */
34
35#ifdef NDEBUG
36#undef NDEBUG
37#endif
38#include "CompilerWarnings.hh"
39IGNORE_COMPILER_WARNING("-Wunused-parameter")
40IGNORE_COMPILER_WARNING("-Wcomment")
41
42#include <llvm/Analysis/LoopInfo.h>
43#include <llvm/Analysis/LoopPass.h>
44
45#include "tce_config.h"
46#include <llvm/IR/Dominators.h>
47
48#include <llvm/Analysis/AliasAnalysis.h>
49#include <llvm/IR/LegacyPassManager.h>
50#include <llvm/Pass.h>
51
52#include <llvm/CodeGen/AsmPrinter.h>
53#include <llvm/CodeGen/Passes.h>
54
55#include <llvm/Target/TargetMachine.h>
56#include <llvm/Target/TargetOptions.h>
57
58#include <llvm/Transforms/IPO.h>
59#include <llvm/Transforms/Scalar.h>
60
61#include <llvm/Support/CommandLine.h>
62#include <llvm/Support/FormattedStream.h>
63#include <llvm/Support/MemoryBuffer.h>
64#include <llvm/Support/Debug.h>
65#include <llvm/CodeGen/RegAllocRegistry.h>
66#include "Application.hh"
67#include <llvm/IR/Module.h>
68#include <llvm/IR/LLVMContext.h>
69
70#include <llvm/Bitcode/BitcodeReader.h>
71
72#include <llvm/IR/Verifier.h>
73
74#include <llvm/IR/GCStrategy.h>
75
76#include <llvm-c/Core.h> // LLVMGetGlobalContext()
77
78// tce_config.h defines these. this undef to avoid warning.
79// TODO: how to do this in tce_config.h???
80#ifdef LLVM_LIBDIR
81#undef LLVM_LIBDIR
82#endif
83#include "tce_config.h" // to get llvm version
84
85#include "llvm/MC/TargetRegistry.h"
86
87#include "llvm/Support/FileSystem.h"
88
89#include <llvm/InitializePasses.h>
90
91// cheat llvm's multi-include-protection
92#define CONFIG_H
93
94#include <cstdlib> // system()
95#include <fstream>
96
97#include "LLVMBackend.hh"
99#include "TDGen.hh"
100
102#include "Environment.hh"
103#include "Conversion.hh"
104#include "FileSystem.hh"
105#include "TCETargetMachine.hh"
108#include "LLVMPOMBuilder.hh"
109#include "Program.hh"
110#include "ADFSerializer.hh"
111#include "MachineValidator.hh"
113#include "Instruction.hh"
114#include "ProgramAnnotation.hh"
115#include "TCEString.hh"
116#include "InterPassData.hh"
117#include "InterPassDatum.hh"
118#include "LLVMTCEIRBuilder.hh"
119#include "Machine.hh"
120#include "MachineInfo.hh"
121#include "ConstantTransformer.hh"
122//#define DEBUG_TDGEN
123
124#define DS TCEString(FileSystem::DIRECTORY_SEPARATOR)
125
126using namespace llvm;
127
128#include <llvm/IR/IRPrintingPasses.h>
129
130#include "llvm/IR/DataLayout.h"
131typedef llvm::DataLayout TargetData;
132
134
135const std::string LLVMBackend::TBLGEN_INCLUDES = "";
136const std::string LLVMBackend::PLUGIN_PREFIX = "tcecc-";
137const std::string LLVMBackend::PLUGIN_SUFFIX = ".so";
138const TCEString LLVMBackend::CXX0X_FLAG = "-std=c++0x";
139const TCEString LLVMBackend::CXX11_FLAG = "-std=c++11";
140const TCEString LLVMBackend::CXX14_FLAG = "-std=c++14";
141const TCEString LLVMBackend::CXX17_FLAG = "-std=c++17";
142
144
145/**
146 * Returns minimum opset that is required by llvm.
147 *
148 * @return Minimumn opset that is required for llvm.
149 */
151LLVMBackend::llvmRequiredOpset(bool includeFloatOps, bool littleEndian, bool bits64) {
153
154 if (littleEndian) {
155 requiredOps.insert("LD32");
156 requiredOps.insert("LD16");
157 requiredOps.insert("LDU16");
158 requiredOps.insert("LD8");
159 requiredOps.insert("LDU8");
160 requiredOps.insert("ST32");
161 requiredOps.insert("ST16");
162 requiredOps.insert("ST8");
163 } else {
164 requiredOps.insert("LDW");
165 requiredOps.insert("LDH");
166 requiredOps.insert("LDHU");
167 requiredOps.insert("LDQ");
168 requiredOps.insert("LDQU");
169 requiredOps.insert("STW");
170 requiredOps.insert("STH");
171 requiredOps.insert("STQ");
172 }
173
174 // -- Floating point operations --
175 if (includeFloatOps) {
176 requiredOps.insert("ADDF");
177 requiredOps.insert("SUBF");
178 requiredOps.insert("MULF");
179 requiredOps.insert("DIVF");
180 requiredOps.insert("NEGF");
181 requiredOps.insert("SQRTF");
182
183 requiredOps.insert("CFI");
184 requiredOps.insert("CFIU");
185 requiredOps.insert("CIF");
186 requiredOps.insert("CIFU");
187
188 // Ordered FP comparison operations
189 requiredOps.insert("EQF");
190 requiredOps.insert("NEF");
191 requiredOps.insert("LTF");
192 requiredOps.insert("LEF");
193 requiredOps.insert("GTF");
194 requiredOps.insert("GEF");
195
196 // Unordered FP comparison operations
197 requiredOps.insert("EQUF");
198 requiredOps.insert("NEUF");
199 requiredOps.insert("LTUF");
200 requiredOps.insert("LEUF");
201 requiredOps.insert("GTUF");
202 requiredOps.insert("GEUF");
203
204 // Ordered/unordered operations
205 requiredOps.insert("ORDF");
206 requiredOps.insert("UORDF");
207
208 if (bits64) {
209 requiredOps.insert("ADDD");
210 requiredOps.insert("SUBD");
211 requiredOps.insert("MULD");
212 requiredOps.insert("DIVD");
213 requiredOps.insert("NEGD");
214 requiredOps.insert("SQRTD");
215
216 requiredOps.insert("CDL");
217 requiredOps.insert("CDLU");
218 requiredOps.insert("CLD");
219 requiredOps.insert("CLDU");
220
221 requiredOps.insert("CFD");
222 requiredOps.insert("CDF");
223
224 // Ordered FP comparison operations
225 requiredOps.insert("EQD");
226 requiredOps.insert("NED");
227 requiredOps.insert("LTD");
228 requiredOps.insert("LED");
229 requiredOps.insert("GTD");
230 requiredOps.insert("GED");
231
232 // Unordered FP comparison operations
233 requiredOps.insert("EQUD");
234 requiredOps.insert("NEUD");
235 requiredOps.insert("LTUD");
236 requiredOps.insert("LEUD");
237 requiredOps.insert("GTUD");
238 requiredOps.insert("GEUD");
239
240 // Ordered/unordered operations
241 requiredOps.insert("ORDD");
242 requiredOps.insert("UORDD");
243 }
244 }
245
246 if (bits64) {
247 requiredOps.insert("LDU32"); // TODO not really needed?
248 requiredOps.insert("LD64");
249 requiredOps.insert("ST64");
250
251 requiredOps.insert("ADD64");
252 requiredOps.insert("SUB64");
253 requiredOps.insert("MUL64");
254 requiredOps.insert("DIV64");
255 requiredOps.insert("DIVU64");
256 requiredOps.insert("DIV64");
257 requiredOps.insert("MOD64");
258 requiredOps.insert("MODU64");
259
260 requiredOps.insert("SXH64");
261 requiredOps.insert("SXQ64");
262
263 requiredOps.insert("AND64");
264 requiredOps.insert("XOR64");
265 requiredOps.insert("IOR64");
266
267 requiredOps.insert("SHL64");
268 requiredOps.insert("SHR64");
269 requiredOps.insert("SHRU64");
270
271 requiredOps.insert("EQ64");
272 requiredOps.insert("NE64");
273 requiredOps.insert("LT64");
274 requiredOps.insert("LTU64");
275 requiredOps.insert("LE64");
276 requiredOps.insert("LEU64");
277 requiredOps.insert("GT64");
278 requiredOps.insert("GTU64");
279 requiredOps.insert("GE64");
280 requiredOps.insert("GEU64");
281
282 return requiredOps;
283 } else {
284 requiredOps.insert("ADD");
285 requiredOps.insert("SUB");
286 requiredOps.insert("MUL");
287 requiredOps.insert("DIV");
288 requiredOps.insert("DIVU");
289 requiredOps.insert("DIV");
290 requiredOps.insert("MOD");
291 requiredOps.insert("MODU");
292
293 requiredOps.insert("SXHW");
294 requiredOps.insert("SXQW");
295
296 requiredOps.insert("AND");
297 requiredOps.insert("XOR");
298 requiredOps.insert("IOR");
299
300 requiredOps.insert("SHL");
301 requiredOps.insert("SHR");
302 requiredOps.insert("SHRU");
303
304 requiredOps.insert("EQ");
305 requiredOps.insert("NE");
306 requiredOps.insert("LT");
307 requiredOps.insert("LTU");
308 requiredOps.insert("LE");
309 requiredOps.insert("LEU");
310 requiredOps.insert("GT");
311 requiredOps.insert("GTU");
312 requiredOps.insert("GE");
313 requiredOps.insert("GEU");
314 }
315 return requiredOps;
316}
317/**
318 * Constructor.
319 *
320 * @param useInstalledVersion Should be true in case we are running an
321 * installed TCE (not from the source/build tree).
322 * @param tempDir An existing directory where to store temporary files.
323 * The directory should be removed by the caller after use.
324 */
325LLVMBackend::LLVMBackend(bool useInstalledVersion, TCEString tempDir) :
326 useInstalledVersion_(useInstalledVersion), tempDir_(tempDir), mach_(NULL),
327 pluginGen_(NULL) {
328
330
331 options_ =
333
334 if (options_ != NULL)
336
337 PassRegistry &Registry = *llvm::PassRegistry::getPassRegistry();
338 llvm::initializeCore(Registry);
339 llvm::initializeScalarOpts(Registry);
340 llvm::initializeIPO(Registry);
341 llvm::initializeAnalysis(Registry);
342 llvm::initializeTransformUtils(Registry);
343 llvm::initializeInstCombine(Registry);
344 llvm::initializeTarget(Registry);
345}
346
347/**
348 * Destructor.
349 */
351 if (pluginGen_ != NULL) {
352 delete pluginGen_;
353 }
354 pluginGen_ = NULL;
355
356}
357
358/**
359 * Sets the target machine and creates a plugin generator for it.
360 *
361 * @param target The target machine
362*/
363
364void
366 mach_ = &target;
367 if (pluginGen_ != NULL) {
368 delete pluginGen_;
369 }
370 pluginGen_ = new TDGen(target);
371}
372
373/**
374 * Compiles bytecode for the given target machine.
375 *
376 * @param bytecodeFile Full path to the llvm bytecode file to compile.
377 * @param optLevel Optimization level.
378 * @param debug If true, enable LLVM debug printing.
379 */
382 const std::string& bytecodeFile, const std::string& emulationBytecodeFile,
383 int optLevel, bool debug, InterPassData* ipData) {
384
385 assert(mach_ != NULL && "Machine not set, forgot to call setMachine()?");
386 // Check target machine
387 MachineValidator validator(*mach_);
388 std::set<MachineValidator::ErrorCode> checks;
389 checks.insert(MachineValidator::GCU_MISSING);
395 MachineValidatorResults* res = validator.validate(checks);
396
397 if (res->errorCount() > 0) {
398 std::string msg;
399 for (int i = 0; i < res->errorCount(); i++) {
400 msg += res->error(i).second + "\n";
401 }
402 delete res; res = NULL;
403 throw CompileError(__FILE__, __LINE__, __func__, msg);
404 }
405
406 // Load bytecode file.
407 std::string errMsgParse;
408 LLVMContext context;
409
410 std::unique_ptr<llvm::Module> m;
411
412 ErrorOr<std::unique_ptr<MemoryBuffer>> bufferPtr =
413 MemoryBuffer::getFileOrSTDIN(bytecodeFile.c_str());
414
415 if (std::error_code ec = bufferPtr.getError()) {
416 std::string msg = "Error reading bytecode file: " + bytecodeFile +
417 "\n" + ec.message();
418 throw CompileError(__FILE__, __LINE__, __func__, msg);
419 }
420
421 // todo: what are these buffers..
422 std::unique_ptr<MemoryBuffer> buffer = std::move(bufferPtr.get());
423 Expected<std::unique_ptr<llvm::Module> > module =
424 parseBitcodeFile(buffer.get()->getMemBufferRef(), context);
425 if (Error E = module.takeError()) {
426 THROW_EXCEPTION(CompileError, "Error parsing bytecode file: "
427 + bytecodeFile);
428 }
429
430 // TODO: why does this work? it should not?
431// m.reset(module.get().get());
432 m = std::move(module.get());
433
434 if (m.get() == 0) {
435 std::string msg = "Error parsing bytecode file: " + bytecodeFile +
436 "\n" + errMsgParse;
437 throw CompileError(__FILE__, __LINE__, __func__, msg);
438 }
439
440 std::unique_ptr<Module> emuM;
441
442 if (!emulationBytecodeFile.empty()) {
443 ErrorOr<std::unique_ptr<MemoryBuffer>> emuBufferPtr =
444 MemoryBuffer::getFileOrSTDIN(emulationBytecodeFile.c_str());
445
446 if (std::error_code ec = emuBufferPtr.getError()) {
447 std::string msg = "Error reading bytecode file: " +
448 emulationBytecodeFile +
449 " of emulation library:\n" + ec.message();
450 throw CompileError(__FILE__, __LINE__, __func__, msg);
451 }
452
453 std::unique_ptr<MemoryBuffer> emuBuffer =
454 std::move(emuBufferPtr.get());
455 Expected<std::unique_ptr<Module> > module =
456 parseBitcodeFile(emuBuffer.get()->getMemBufferRef(), context);
457 if (Error E = module.takeError()) {
458 THROW_EXCEPTION(CompileError, "Error parsing bytecode file: " +
459 emulationBytecodeFile + " of emulation library \n"
460 + errMsgParse);
461 }
462
463 emuM = std::move(module.get());
464 if (emuM.get() == 0) {
465 std::string msg = "Error parsing bytecode file: " +
466 emulationBytecodeFile + " of emulation library \n"
467 + errMsgParse;
468 throw CompileError(__FILE__, __LINE__, __func__, msg);
469 }
470 }
471
472 // Create target machine plugin.
473#if (!defined(HAVE_CXX11) && !defined(HAVE_CXX0X))
474 std::auto_ptr<TCETargetMachinePlugin> plugin(createPlugin());
475#else
476 std::unique_ptr<TCETargetMachinePlugin> plugin(createPlugin());
477#endif
478
479 TTAProgram::Program* result = NULL;
480 try {
481 // Compile.
482 result =
483 compile(*m.release(), emuM.release(), *plugin, optLevel,
484 debug, ipData);
485 } catch (...) {
486 // delete the backend plugin if we don't want to save it
487 // Let's hope this doesn't crash as the plugin is loaded to the
488 // current process. TCETargetMachinePlugin dtor should unload it.
489 if (!options_->saveBackendPlugin()) {
490 TCEString pluginPath =
493 }
494 delete res; res = NULL;
495
496 throw;
497 }
498
499 // delete the backend plugin if we don't want to save it
500 // Let's hope this doesn't crash as the plugin is loaded to the
501 // current process. TCETargetMachinePlugin dtor should unload it.
502 if (!options_->saveBackendPlugin()) {
503 TCEString pluginPath =
506 }
507 delete res; res = NULL;
508
509 return result;
510}
511
512/**
513 * Ripped from LLVMTargetMachine.cpp
514
515static void printAndVerify(PassManagerBase &PM,
516 bool allowDoubleDefs = false,
517 bool printMF = false) {
518 if (printMF) {
519 PM.add(createMachineFunctionPrinterPass(cerr));
520 }
521 PM.add(createMachineVerifierPass(allowDoubleDefs));
522}
523*/
524
525/**
526 * Finds the maximum alignment of an alloca in the module.
527 *
528 * Used to align the stack for the program image.
529 */
530unsigned
531LLVMBackend::maxAllocaAlignment(const llvm::Module& mod) const {
532 unsigned maxAlignment = 4;
533 for (llvm::Module::const_iterator f = mod.begin(),
534 fe = mod.end(); f != fe; ++f) {
535 for (llvm::Function::const_iterator bb = f->begin(), be = f->end();
536 bb != be; ++bb) {
537 const llvm::BasicBlock* basicBlock = &(*bb);
538 for (llvm::BasicBlock::const_iterator i = basicBlock->begin(),
539 ie = basicBlock->end(); i != ie; ++i) {
540 if (!isa<const llvm::AllocaInst>(i)) continue;
541 const llvm::AllocaInst* alloca =
542 dyn_cast<const llvm::AllocaInst>(i);
543 #ifdef LLVM_OLDER_THAN_15
544 maxAlignment = std::max(maxAlignment,
545 (unsigned)alloca->getAlign().value());
546 maxAlignment = std::max(maxAlignment,
547 (unsigned)alloca->getAlignment());
548 #else
549 maxAlignment = std::max(maxAlignment,
550 (unsigned)alloca->getAlign().value());
551 maxAlignment = std::max(maxAlignment,
552 (unsigned)alloca->getAlign().value());
553 #endif
554
555 }
556 }
557 }
558 return maxAlignment;
559}
560
561static MCRegisterInfo*
562createTCEMCRegisterInfo(const Triple& TT) {
563 MCRegisterInfo* X = new MCRegisterInfo();
564 return X;
565}
566
567static MCInstrInfo*
569 MCInstrInfo* X = new MCInstrInfo();
570 return X;
571}
572
573static MCSubtargetInfo*
574createTCEMCSubtargetInfo(const Triple& TT, StringRef CPU, StringRef FS) {
575 const MCWriteProcResEntry WPR[] = {{0, 0}};
576 const MCWriteLatencyEntry WL[] = {{0, 0}};
577 const MCReadAdvanceEntry RA[] = {{0, 0, 0}};
578 ArrayRef<SubtargetFeatureKV> PF;
579 ArrayRef<SubtargetSubTypeKV> PD;
580
581 MCSubtargetInfo* X = new MCSubtargetInfo(
582 TT, CPU, /*TuneCPU*/ "", FS, PF, PD, WPR, WL, RA, nullptr, nullptr,
583 nullptr);
584
585 return X;
586}
587
588/**
589 * Compiles given llvm program module for target machine using the given
590 * target machine plugin.
591 *
592 * @param module LLVM module to compile.
593 * @param plugin Target architecture compiler plugin.
594 * @param optLevel Optimization level.
595 * @param debug If true, enable LLVM debug printing.
596 * @return Module compiled to program for the target architecture.
597 */
600 llvm::Module& module, llvm::Module* emulationModule,
601 TCETargetMachinePlugin& plugin, int optLevel,
602 bool /*debug*/, InterPassData* ipData) {
603 assert(mach_ != NULL && "Machine not set, forgot to call setMachine()?");
604 ipData_ = ipData;
605 // TODO: fixme
606 std::string targetStr = "tce-llvm";
607 if (mach_->isLittleEndian()) {
608 if (mach_->is64bit()) {
609 targetStr = "tcele64-llvm";
610 } else {
611 targetStr = "tcele-llvm";
612 }
613 }
614
615 std::string errorStr;
616
617 std::string featureString ="";
618
619 // run registering code, which should have been done by LLVM
620
621 // Initialize targets first. needs
622 // #include <llvm/Target/TargetSelecty.h>,
623 // whose defines collide with tce_config.h
624
625 //InitializeAllTargets();
626 //InitializeAllAsmPrinters();
627
628 // Register target to llvm for using lookupTarget
631
632 // get registered target machine and set plugin.
633 const Target* tceTarget =
634 TargetRegistry::lookupTarget(targetStr, errorStr);
635 Target* nonconst_target = const_cast<Target*>(tceTarget);
636
637 if (!tceTarget) {
638 errs() << errorStr << "\n";
639 return NULL;
640 }
641
642 TargetRegistry::RegisterMCRegInfo(
643 *nonconst_target, createTCEMCRegisterInfo);
644 TargetRegistry::RegisterMCInstrInfo(
645 *nonconst_target, createTCEMCInstrInfo);
646 TargetRegistry::RegisterMCSubtargetInfo(
647 *nonconst_target, createTCEMCSubtargetInfo);
648
649 std::string cpuStr = "tce";
650
651 TargetOptions Options;
652 Options.UnsafeFPMath = false; //EnableUnsafeFPMath;
653 Options.NoInfsFPMath = false; //EnableNoInfsFPMath;
654 Options.NoNaNsFPMath = false; //EnableNoNaNsFPMath;
655 Options.HonorSignDependentRoundingFPMathOption = false;
656 // the stack alignment depends on the widest aligned
657 // memory operations supported by the machine and
658 // on the maximum alignment of any stack object in
659 // the program, recompute this now as the llvm::Module has
660 // been loaded
661 unsigned maxMachineAlignment = (unsigned)MachineInfo::maxMemoryAlignment(*mach_);
662 module.setOverrideStackAlignment(maxMachineAlignment);
664
665 if (maxAllocaAlignment(module) > maxMachineAlignment) {
667 "Alloca object requires larger stack alignment than widest "
668 "memory operation. "
669 "We were hoping this wouldn't happen, because now stack "
670 "alignment cannot be "
671 "figured out just from adf-file. ATM (5/20) this assumption is "
672 "made here, "
673 "at tcecc::getStackAlignment and at CodeGenerator.cc "
674 "constructor.");
675 }
676 } else {
677 module.setOverrideStackAlignment(
678 std::max(maxMachineAlignment, maxAllocaAlignment(module)));
679 }
680 Options.GuaranteedTailCallOpt = true; //EnableGuaranteedTailCallOpt;
681
682 TCETargetMachine* targetMachine =
683 static_cast<TCETargetMachine*>(
684 tceTarget->createTargetMachine(
685 targetStr, cpuStr, featureString, Options,
686 Reloc::Model::Static));
687
688 if (!targetMachine) {
689 errs() << "Could not create tce target machine" << "\n";
690 return NULL;
691 }
692 // The way to override the stack alignment was
693 // changed in LLVM commit 787ee457173c. It's easiest
694 // we just pass it through TCETargetMachine for now
695 // even though it's really module specific.
696 targetMachine->setStackAlignment(
697 std::max((unsigned)(mach_->is64bit() ? 8 : 4),
698 module.getOverrideStackAlignment()));
699
700 // This hack must be cleaned up before adding TCE target to llvm upstream
701 // these are needed by TCETargetMachine::addInstSelector passes
702 targetMachine->setTargetMachinePlugin(plugin, *mach_);
703 targetMachine->setEmulationModule(emulationModule);
704
705 /**
706 * This is quite straight copy how llc actually creates passes for target.
707 */
708
709 llvm::legacy::PassManager Passes;
710#define addPass(P) Passes.add(P)
711
712 llvm::raw_fd_ostream sos(STDOUT_FILENO, false);
713
714 targetMachine->addPassesToEmitFile(
715 Passes, sos, nullptr, CGFT_AssemblyFile);
716
717
718 // Add alias analysis pass that is distributed with pocl library.
720 ImmutablePass* (*creator)();
721 std::string file = options_->workItemAAFile();
722 bool foundAA = true;
723 try {
725 "create_workitem_aa_plugin", creator, file);
726 } catch(Exception& e) {
727 std::string msg = std::string() +
728 "Unable to load plugin file '" +
729 file + "'. Error: " + e.errorMessageStack();
730 if (Application::verboseLevel() > 0) {
732 << msg << std::endl;
734 "Most likely too old version of POCL. \
735 TCE will continue without work item alias analysis." <<
736 std::endl;
737 }
738 foundAA = false;
739 }
740 if (foundAA)
741 addPass(creator());
742 }
743 if (ipData_ != NULL) {
744 // Stack pointer datum.
745 RegDatum* spReg = new RegDatum;
746 spReg->first = plugin.rfName(plugin.spDRegNum());
747 spReg->second = plugin.registerIndex(plugin.spDRegNum());
748 ipData_->setDatum("STACK_POINTER", spReg);
749
750 // FP register datum.
751 RegDatum* fpReg = new RegDatum;
752 fpReg->first = plugin.rfName(plugin.fpDRegNum());
753 fpReg->second = plugin.registerIndex(plugin.fpDRegNum());
754 ipData_->setDatum("FRAME_POINTER", fpReg);
755
756 // Return value register datum.
757 RegDatum* rvReg = new RegDatum;
758 rvReg->first = plugin.rfName(plugin.rvDRegNum());
759 rvReg->second = plugin.registerIndex(plugin.rvDRegNum());
760 ipData_->setDatum("RV_REGISTER", rvReg);
761
762 std::vector<unsigned> paramRegs = plugin.getParamDRegNums();
763 for (unsigned int i = 0; i < paramRegs.size(); i++) {
764 RegDatum* p = new RegDatum;
765 p->first = plugin.rfName(paramRegs[i]);
766 p->second = plugin.registerIndex(paramRegs[i]);
767 TCEString datumName = "IPARAM";
768 datumName << i+2;
769 ipData_->setDatum(datumName, p);
770 }
771
772 std::vector<unsigned> vectorRVRegs = plugin.getVectorRVDRegNums();
773 for (unsigned int i = 0; i < vectorRVRegs.size(); i++) {
774 RegDatum* p = new RegDatum;
775 p->first = plugin.rfName(vectorRVRegs[i]);
776 p->second = plugin.registerIndex(vectorRVRegs[i]);
777 TCEString datumName = "VRV_REGISTER";
778 datumName << i;
779 ipData_->setDatum(datumName, p);
780 }
781
782 // TODO: add datums for vector RV registers.
783 }
784
785 // Find the inner loops. Must be executed with a separate
786 // PassManager as mixing module passes and loop passes does
787 // not seem to magically work.
788 // TODO: is it safe to trust the llvm::BasicBlock pointers are
789 // intact until we run the actual code generation? The loop info
790 // is stored using those as indices.
791 llvm::legacy::PassManager FPasses;
792 InnerLoopFinder* loopFinder = new InnerLoopFinder();
793 FPasses.add(loopFinder);
794 FPasses.run(module);
795
796 LLVMTCEBuilder* builder = NULL;
797
798 // This is not actuall LLVM pass so we can not get actual AA.
799 // It will be picked later, for now just passing NULL.
800 // When LLVMTCEIRBuilder is called from TCEScheduler it will require
801 // AA parameter.
802 AliasAnalysis* AA = NULL;
803 LLVMTCEIRBuilder* b =
804 new LLVMTCEIRBuilder(*targetMachine, mach_, *ipData, AA);
805 b->setInnerLoopFinder(loopFinder);
806 builder = b;
807
811 }
813 addPass(builder);
814 Passes.run(module);
815
816 if (ipData_ != NULL) {
817 if (builder->isProgramUsingRestrictedPointers()) {
818 ipData_->setDatum("RESTRICTED_POINTERS_FOUND", NULL);
819 }
820 }
821 builder->deleteDeadProcedures();
822 return builder->result();
823}
824
825/**
826 * Creates TCETargetMachinePlugin for target architecture.
827 */
830 assert(mach_ != NULL && "Machine not set, forgot to call setMachine()?");
831 std::string pluginFile = pluginFilename();
832 std::string pluginFileName;
833
834 // Create cache directory if it doesn't exist.
837 }
838
839 pluginFileName = cachePath_ + DS + pluginFile;
840
841 llvm::SmallString<128> ResultPath;
842
843 // Static plugin source files path.
844 std::string srcsPath = "";
845 std::string pluginIncludeFlags = "";
847 srcsPath = Application::installationDir() + DS + "include" + DS;
848 pluginIncludeFlags = " -I" + srcsPath;
849 } else {
850 srcsPath = std::string(TCE_SRC_ROOT) + DS +
851 "src" + DS + "applibs" + DS + "LLVMBackend" + DS + "plugin" + DS;
852
853 pluginIncludeFlags =
854 " -I" + srcsPath +
855 " -I" + std::string(TCE_SRC_ROOT) + DS + " " +
856 " -I" + std::string(TCE_SRC_ROOT) + DS + "src" + DS + "tools" +
857 " -I" + std::string(TCE_SRC_ROOT) + DS + "src" + DS + "base" +
858 DS + "mach"
859 " -I" + std::string(TCE_SRC_ROOT) + DS + "src" + DS +
860 "applibs" + DS + "LLVMBackend" + DS + " " +
861
862 " -I" + std::string(TCE_SRC_ROOT) + DS + "src" + DS +
863 "applibs" + DS + "mach" + " " +
864
865 " -I" + std::string(TCE_SRC_ROOT) + DS + "src" + DS +
866 "applibs" + DS + "Scheduler" + DS + " " +
867
868 " -I" + std::string(TCE_SRC_ROOT) + DS + "src" + DS +
869 "applibs" + DS + "Scheduler" + DS + "Algorithms" + " " +
870
871 " -I`" LLVM_CONFIG " --includedir`" + DS + "llvm" + DS +
872 "Target" + DS;
873
874 }
875
876
877 if (FileSystem::fileExists(pluginFileName) &&
878 FileSystem::fileIsReadable(pluginFileName)) {
879
880 try {
882 pluginTool_.registerModule(pluginFile);
883 TCETargetMachinePlugin* (*creator)();
885 "create_tce_backend_plugin", creator, pluginFile);
886
887 return creator();
888 } catch(Exception& e) {
889 if (Application::verboseLevel() > 0) {
891 << "Unable to load plugin file " << pluginFileName
892 << ": " << e.errorMessage() << ", "
893 << "regenerating..." << std::endl;
894 }
895 }
896 }
897
899 // Create target instruction and register definitions in .td files
900
901
902 try {
904 } catch(Exception& e) {
905 std::string msg =
906 "Failed to build compiler plugin for target architecture: ";
907 msg += e.errorMessage();
908 CompileError ne(__FILE__, __LINE__, __func__, msg);
909 ne.setCause(e);
910 throw ne;
911 }
912 }
913 std::string tblgenbin = "llvm-tblgen";
914
915 // Generate TCEGenRegisterNames.inc
916 std::string tblgenCmd;
917
919 // This is quite ugly. LLVM include dir is determined by
920 // executing llvm-config in the commandline. This doesn't
921 // work if llvm-config is not found in path.
922 // First check that llvm-config is found in path.
923 if (system(LLVM_CONFIG " --version")) {
924 std::string msg = "Unable to determine llvm include dir. "
925 LLVM_CONFIG " not found in path";
926
927 throw CompileError(__FILE__, __LINE__, __func__, msg);
928 }
929 // /usr/include needs to be last in case there is old llvm installation
930 // from packages
931 tblgenCmd = tblgenbin + " " + TBLGEN_INCLUDES +
932 pluginIncludeFlags +
933 " -I" + tempDir_ +
934 " -I`" LLVM_CONFIG " --includedir`" +
935 " -I`" LLVM_CONFIG " --includedir`/Target" +
936 " -I`" LLVM_CONFIG " --includedir`/llvm/Target" +
937 " -I/usr/include ";
938 } else {
939 tblgenCmd = tblgenbin + " " + TBLGEN_INCLUDES +
940 pluginIncludeFlags +
941 " -I" + tempDir_ +
942 " -I" + LLVM_INCLUDE_DIR +
943 " -I" + LLVM_INCLUDE_DIR + "/Target" +
944 " -I" + LLVM_INCLUDE_DIR + "/llvm/Target";
945 }
946
947 tblgenCmd += " " + tempDir_ + FileSystem::DIRECTORY_SEPARATOR + "TCE.td";
948
949 // Generate TCEGenRegisterInfo.inc
950 std::string cmd = tblgenCmd +
951 " -gen-register-info" +
953 "TCEGenRegisterInfo.inc";
954
955 if (Application::verboseLevel() > 0) {
956 Application::logStream() << "LLVMBackend: " << cmd << std::endl;
957 }
958 int ret = system(cmd.c_str());
959 if (ret) {
960 std::string msg = std::string() +
961 "Failed to build compiler plugin for target architecture.\n" +
962 "Failed command was: " + cmd;
963
964 throw CompileError(__FILE__, __LINE__, __func__, msg);
965 }
966
967 // Generate TCEGenInstrInfo.inc
968 cmd = tblgenCmd +
969 " -gen-instr-info" +
971 "TCEGenInstrInfo.inc";
972
973 ret = system(cmd.c_str());
974 if (ret) {
975 std::string msg = std::string() +
976 "Failed to build compiler plugin for target architecture.\n" +
977 "Failed command was: " + cmd;
978
979 throw CompileError(__FILE__, __LINE__, __func__, msg);
980 }
981
982 // Generate TCEGenDAGISel.inc
983 cmd = tblgenCmd +
984 " -gen-dag-isel" +
986 "TCEGenDAGISel.inc";
987
988 ret = system(cmd.c_str());
989 if (ret) {
990 std::string msg = std::string() +
991 "Failed to build compiler plugin for target architecture.\n" +
992 "Failed command was: " + cmd;
993
994 throw CompileError(__FILE__, __LINE__, __func__, msg);
995 }
996
997
998 // Generate TCEGenCallingConv.inc
999 cmd = tblgenCmd +
1000 " -gen-callingconv" +
1002 "TCEGenCallingConv.inc";
1003
1004 ret = system(cmd.c_str());
1005 if (ret) {
1006 std::string msg = std::string() +
1007 "Failed to build compiler plugin for target architecture.\n" +
1008 "Failed command was: " + cmd;
1009
1010 throw CompileError(__FILE__, __LINE__, __func__, msg);
1011 }
1012
1013 // Generate TCESuBTargetInfo.inc
1014 cmd = tblgenCmd +
1015 " -gen-subtarget" +
1017 "TCEGenSubTargetInfo.inc";
1018
1019 ret = system(cmd.c_str());
1020 if (ret) {
1021 std::string msg =
1022 std::string() +
1023 "Failed to build compiler plugin for target architecture.\n" +
1024 "Failed command was: " + cmd;
1025
1026 throw CompileError(__FILE__, __LINE__, __func__, msg);
1027 }
1028
1029 // Generate TCEDFAPacketizer.inc
1030 cmd = tblgenCmd + " -gen-dfa-packetizer" + " -o " + tempDir_ +
1031 FileSystem::DIRECTORY_SEPARATOR + "TCEGenDFAPacketizer.inc";
1032
1033 ret = system(cmd.c_str());
1034 if (ret) {
1035 std::string msg =
1036 std::string() +
1037 "Failed to build compiler plugin for target architecture.\n" +
1038 "Failed command was: " + cmd;
1039
1040 throw CompileError(__FILE__, __LINE__, __func__, msg);
1041 }
1042
1043 // NOTE: this could be get from Makefile.am
1044 TCEString pluginSources = srcsPath + "PluginCompileWrapper.cc ";
1045
1046 TCEString endianOption = mach_->isLittleEndian() ?
1047 "-DLITTLE_ENDIAN_TARGET" : "";
1048
1049 TCEString bitnessOption = mach_->is64bit() ? "-DTARGET64BIT" : "";
1050
1051 std::string tempPluginFileName;
1052 tempPluginFileName = cachePath_ + DS + pluginFile + ".%%_%%_%%_%%";
1053 llvm::sys::fs::createUniqueFile(llvm::Twine(tempPluginFileName), ResultPath);
1054 tempPluginFileName = ResultPath.str().str();
1055 // Compile plugin to cache.
1056 // CXX and SHARED_CXX_FLAGS defined in tce_config.h
1057 cmd = std::string(CXX) +
1058 " -I" + tempDir_ +
1059 pluginIncludeFlags +
1060 " " + SHARED_CXX_FLAGS +
1061 " " + LLVM_CPPFLAGS;
1062
1064 cmd += " -I`" LLVM_CONFIG " --includedir`";
1065
1066 cmd +=
1067 #ifdef LLVM_OLDER_THAN_16
1068 " " + CXX14_FLAG +
1069 #else
1070 " " + CXX17_FLAG +
1071 #endif
1072 " " + endianOption +
1073 " " + bitnessOption +
1074 " " + pluginSources +
1075 " -o " + tempPluginFileName;
1076
1077 if (Application::verboseLevel() > 0) {
1078 Application::logStream() << "LLVMBackend: " << cmd << std::endl;
1079 }
1080 ret = system(cmd.c_str());
1081 if (ret) {
1082 std::string msg = std::string() +
1083 "Failed to build compiler plugin for target architecture.\n" +
1084 "Failed command was: " + cmd;
1085
1086 throw CompileError(__FILE__, __LINE__, __func__, msg);
1087 }
1088
1089 // move plugin to final location
1090 llvm::sys::fs::rename(llvm::Twine(tempPluginFileName), llvm::Twine(pluginFileName));
1091
1092 // Load plugin.
1093 TCETargetMachinePlugin* (*creator)();
1094 try {
1096 pluginTool_.registerModule(pluginFile);
1098 "create_tce_backend_plugin", creator, pluginFile);
1099 } catch(Exception& e) {
1100 std::string msg = std::string() +
1101 "Unable to load plugin file '" +
1102 pluginFileName + "'. Error: " + e.errorMessage();
1103
1104 IOException ne(__FILE__, __LINE__, __func__, msg);
1105 throw ne;
1106 }
1107
1108 return creator();
1109}
1110
1111/**
1112 * Returns (hopefully) unique plugin filename for target architecture.
1113 *
1114 * The filename includes also the TCE version string to avoid problems with
1115 * incompatible backend plugins between TCE revisions.
1116 * The filename is used for cached plugins.
1117 *
1118 * @return Filename for the target architecture.
1119 */
1120std::string
1122 assert(pluginGen_ != NULL &&
1123 "TDPlugin not set, forgot to call setMachine()?");
1124 const std::string buffer = pluginGen_->generateBackend();
1125
1126 // Generate a hash based on the backend output
1127 boost::hash<std::string> stringHasher;
1128 size_t h = stringHasher(buffer);
1129
1130 TCEString hash =
1131 (Conversion::toHexString(buffer.length())).substr(2);
1132
1133 hash += "_";
1134 hash += (Conversion::toHexString(h)).substr(2);
1135
1136 TCEString fileName = hash;
1137 // add toolset version to the hash
1138 fileName += "-" + Application::TCEVersionString();
1139 fileName += PLUGIN_SUFFIX;
1140
1141 return fileName;
1142}
#define __func__
#define abortWithError(message)
#define assert(condition)
#define IGNORE_COMPILER_WARNING(X)
#define POP_COMPILER_DIAGS
#define THROW_EXCEPTION(exceptionType, message)
Exception wrapper macro that automatically includes file name, line number and function name where th...
Definition Exception.hh:39
static llvm::RegisterPass< InnerLoopFinder > X("find-innerloops-test", "Finds inner loops test.", false, true)
SimpleInterPassDatum< std::pair< TCEString, unsigned int > > RegDatum
Datum type for transferring register name as a data. Stack pointer register is saved with key STACK_P...
#define DS
Pass * createWorkItemAliasAnalysisPass()
static MCSubtargetInfo * createTCEMCSubtargetInfo(const Triple &TT, StringRef CPU, StringRef FS)
llvm::DataLayout TargetData
static MCRegisterInfo * createTCEMCRegisterInfo(const Triple &TT)
#define addPass(P)
static MCInstrInfo * createTCEMCInstrInfo()
#define RA()
void LLVMInitializeTCETargetInfo()
void LLVMInitializeTCETarget()
static CmdLineOptions * cmdLineOptions()
static std::string installationDir()
static std::string TCEVersionString()
static int verboseLevel()
static std::ostream & logStream()
static std::string toHexString(T source, std::size_t digits=0, bool include0x=true)
static std::string llvmtceCachePath()
std::string errorMessageStack(bool messagesOnly=false) const
Definition Exception.cc:138
std::string errorMessage() const
Definition Exception.cc:123
void setCause(const Exception &cause)
Definition Exception.cc:75
static bool fileIsReadable(const std::string fileName)
static bool createDirectory(const std::string &path)
static bool removeFileOrDirectory(const std::string &path)
static const std::string DIRECTORY_SEPARATOR
static bool fileIsDirectory(const std::string fileName)
static bool fileExists(const std::string fileName)
void setDatum(const std::string &key, InterPassDatum *datum)
LLVMTCECmdLineOptions * options_
static const std::string PLUGIN_PREFIX
static const std::string PLUGIN_SUFFIX
TDGen * pluginGen_
bool useInstalledVersion_
Assume we are running an installed TCE version.
InterPassData * ipData_
static const TCEString CXX17_FLAG
llvm::TCETargetMachinePlugin * createPlugin()
TCEString cachePath_
Path to the cache where precompiled plugins are stored.
LLVMBackend(bool useInstalledVersion, TCEString tempDir)
std::string pluginFilename()
TTAProgram::Program * compile(const std::string &bytecodeFile, const std::string &emulationBytecodeFile, int optLevel, bool debug=false, InterPassData *ipData=NULL)
static const std::string TBLGEN_INCLUDES
PluginTools pluginTool_
Plugin tool for loading target machine plugin.
TCEString tempDir_
Directory to store temporary files.
unsigned maxAllocaAlignment(const llvm::Module &mod) const
static OperationDAGSelector::OperationSet llvmRequiredOpset(bool includeFloatOps, bool isLittleEndian, bool bits64)
TTAMachine::Machine * mach_
void setMachine(TTAMachine::Machine &target)
static const TCEString CXX14_FLAG
static const TCEString CXX0X_FLAG
static const TCEString CXX11_FLAG
virtual ~LLVMBackend()
uint64_t initialStackPointerValue() const
std::string workItemAAFile() const
std::string backendCacheDir() const
static int maxMemoryAlignment(const TTAMachine::Machine &mach)
MachineValidatorResults * validate(const std::set< ErrorCode > &errorsToCheck) const
@ GCU_AS_MISSING
Address space missing in GCU.
@ RA_PORT_MISSING
RA port missing in GCU.
@ FU_PORT_MISSING
FU is missing ports.
@ USED_IO_NOT_BOUND
Pipeline uses an IO which is not bound.
@ GCU_MISSING
GCU missing in machine.
@ PC_PORT_MISSING
PC port missing in GCU.
TCETools::CIStringSet OperationSet
void importSymbol(const std::string &symbolName, T *&target, const std::string &module)
void addSearchPath(const std::string &searchPath)
void registerModule(const std::string &module)
Definition TDGen.hh:77
virtual void generateBackend(const std::string &path) const
Definition TDGen.cc:431
bool isLittleEndian() const
Definition Machine.hh:258
bool is64bit() const
Definition Machine.hh:260
bool isProgramUsingRestrictedPointers() const
TTAProgram::Program * result()
void setInitialStackPointerValue(unsigned value)
void setInnerLoopFinder(InnerLoopFinder *loopFinder)
virtual std::vector< unsigned > getParamDRegNums() const =0
virtual std::string rfName(unsigned dwarfRegNum)=0
Returns name of the physical register file corresponding to a generated register ID.
virtual std::vector< unsigned > getVectorRVDRegNums() const =0
virtual unsigned registerIndex(unsigned dwarfRegNum)=0
Returns name of the physical register index corresponding to a generated register ID.
virtual unsigned rvDRegNum()=0
virtual unsigned spDRegNum()=0
Returns ID number of the stack pointer register.
virtual unsigned fpDRegNum()=0
Returns ID number of the frame pointer register.
virtual void setEmulationModule(Module *mod)
void setStackAlignment(unsigned align)
virtual void setTargetMachinePlugin(TCETargetMachinePlugin &plugin, TTAMachine::Machine &target)
AAResults AliasAnalysis