OpenASIP 2.2
Loading...
Searching...
No Matches
LowerMissingInstructions.cc
Go to the documentation of this file.
1/*
2 Copyright (c) 2002-2015 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 LowerMissingInstructions.cc
26 *
27 * Convert instruction which are not supported by the machine to
28 * function calls.
29 *
30 * NOTE: Right now system is limited to replace only those operations, which
31 * use only one bitwidth integers for example i1.icmp.i32.i32 cannot
32 * be lowered to function call.
33 * However i16.mul.i16.i16 works.
34 *
35 * Maybe better way would be to take llvm footprints which must be
36 * emulated and create function prototype directly for them.
37 * @author Mikael Lepisto 2008-2009 (mikael.lepisto-no.spam-tut.fi)
38 * @author Pekka Jaaskelainen 2010
39 * @note reting: red
40 */
41
42#include "CompilerWarnings.hh"
43IGNORE_COMPILER_WARNING("-Wunused-parameter")
44
45#define DEBUG_TYPE "lowermissing"
46
47#include "llvm/Transforms/Scalar.h"
48#include "llvm/Transforms/Utils/UnifyFunctionExitNodes.h"
49#include "tce_config.h"
50#include "llvm/IR/LLVMContext.h"
51#include "llvm/IR/Module.h"
52#include "llvm/IR/DerivedTypes.h"
53#include "llvm/IR/Instructions.h"
54#include "llvm/IR/Constants.h"
55#include "llvm/ADT/Statistic.h"
56#include "llvm/Support/Compiler.h"
57#include "llvm/IR/AbstractCallSite.h"
58#include "llvm/IR/InstrTypes.h" // CreateIntegerCast()
59#include "llvm/ADT/Twine.h"
60
61#include "llvm/ADT/STLExtras.h" // array_endof
62#include "llvm/Support/CommandLine.h" // cl::opt
63
64
65// TCE headers
66// tce_config.h defines these. this undef to avoid warning.
67// TODO: how to do this in tce_config.h???
68#ifdef LLVM_LIBDIR
69#undef LLVM_LIBDIR
70#endif
71
72#include "Machine.hh"
74#include "MachineInfo.hh"
75#include "Operand.hh"
76#include "Operation.hh"
77#include "OperationPool.hh"
78#include "TCEString.hh"
80
81#include "LLVMBackend.hh" // llvmRequiredOps()
82
84
85using namespace llvm;
86
87STATISTIC(NumLowered, "Number of instructions lowered");
88
89#include <iostream>
90
91#define ARGLIST_CONST
92#define TYPE_CONST
93
94namespace {
95 class LowerMissingInstructions : public FunctionPass {
96 std::map< std::string, Function*> replaceFunctions;
97 const TTAMachine::Machine* mach_;
98 Module* dstModule_;
99
100 public:
101 static char ID; // Pass ID, replacement for typeid
102 LowerMissingInstructions(const TTAMachine::Machine& mach);
103
104
105 // from llvm::Pass:
106 bool doInitialization(Module &M) override;
107 bool doFinalization (Module &M) override;
108
109 // to suppress Clang warnings
110 using llvm::FunctionPass::doInitialization;
111 using llvm::FunctionPass::doFinalization;
112
113 bool runOnBasicBlock(BasicBlock &BB);
114 bool runOnFunction(Function &F);
115
116 virtual StringRef getPassName() const override {
117 return "TCE: LowerMissingInstructions";
118 }
119
120 void addFunctionForFootprints(
121 Module& M, FunctionType* fType, Operation& op,
122 std::string suffix);
123
124 private:
125 std::string stringType(const Type* type) const;
126
127 ARGLIST_CONST Type* getLLVMType(
128 Operand::OperandType type, ARGLIST_CONST Type* llvmIntegerType);
129
130 std::string getFootprint(Instruction& I);
131
132 // getGlobalContext() was removed form LLVM.
133 LLVMContext& getGlobalContext() const {
134 return dstModule_->getContext();
135 }
136 };
137
138 char LowerMissingInstructions::ID = 0;
139
140// When we got another way than parameter
141// for passing machine we can register pass to manager
142// RegisterPass<LowerMissingInstructions>
143// X("lowermissing", "Lower missing instructions to libcalls");
144}
145
146// - Interface to this file...
148 return new LowerMissingInstructions(mach);
149}
150
151LowerMissingInstructions::LowerMissingInstructions(
152 const TTAMachine::Machine& mach) :
153 FunctionPass(ID),
154 mach_(&mach) {
155}
156
157// convert type name to string
158std::string
159LowerMissingInstructions::stringType(const Type* type) const {
160 LLVMContext& context = getGlobalContext();
161 if (type == Type::getInt64Ty(context)) {
162 return "i64";
163 } else if (type == Type::getInt32Ty(context)) {
164 return "i32";
165 } else if (type == Type::getInt16Ty(context)) {
166 return "i16";
167 } else if (type == Type::getInt8Ty(context)) {
168 return "i8";
169 } else if (type == Type::getInt1Ty(context)) {
170 return "i1";
171 } else if (type == Type::getHalfTy(context)) {
172 return "f16";
173 } else if (type == Type::getFloatTy(context)) {
174 return "f32";
175 } else if (type == Type::getDoubleTy(context)) {
176 return "f64";
177 } else if (type == Type::getLabelTy(context)) {
178 return "label";
179 } else if (type == Type::getVoidTy(context)) {
180 return "void";
181 } else {
182 return "unknown";
183 }
184}
185
186ARGLIST_CONST Type*
187LowerMissingInstructions::getLLVMType(
188 Operand::OperandType type, ARGLIST_CONST Type* llvmIntegerType) {
189 switch (type) {
191 return llvmIntegerType;
193 return llvmIntegerType;
195 return Type::getInt64Ty(getGlobalContext());
197 return Type::getInt64Ty(getGlobalContext());
199 return Type::getFloatTy(getGlobalContext());
201 return Type::getHalfTy(getGlobalContext());
203 return Type::getDoubleTy(getGlobalContext());
204 default:
205 return Type::getVoidTy(getGlobalContext());
206 }
207}
208
209const std::vector<std::string>& llvmFootprints(std::string tceOp) {
210 static bool init = true;
211 static std::map<std::string, std::vector<std::string> > footprints;
212
213 // NOTE: .i32 is default footprint suffix if there is no i16, i8 or i1
214 // versions.. e.g. .i32 is suffix for f32.fadd.f32.f32
215 if (init) {
216// footprints["DIVU.i32"].push_back("i32.udiv.i32.i32");
217// footprints["DIVU.i16"].push_back("i16.udiv.i16.i16");
218// footprints["DIVU.i8"].push_back("i8.udiv.i8.i8");
219
220// footprints["DIV.i32"].push_back("i32.sdiv.i32.i32");
221// footprints["DIV.i16"].push_back("i16.sdiv.i16.i16");
222// footprints["DIV.i8"].push_back("i8.sdiv.i8.i8");
223
224// footprints["MODU.i32"].push_back("i32.urem.i32.i32");
225// footprints["MODU.i16"].push_back("i16.urem.i16.i16");
226// footprints["MODU.i8"].push_back("i8.urem.i8.i8");
227
228// footprints["MOD.i32"].push_back("i32.rem.i32.i32");
229// footprints["MOD.i16"].push_back("i16.rem.i16.i16");
230// footprints["MOD.i8"].push_back("i8.rem.i8.i8");
231
232// footprints["MUL.i32"].push_back("i32.mul.i32.i32");
233// footprints["MUL.i16"].push_back("i16.mul.i16.i16");
234// footprints["MUL.i8"].push_back("i8.mul.i8.i8");
235 footprints["ADDH.i32"].push_back("f16.fadd.f16.f16");
236 footprints["SUBH.i32"].push_back("f16.fsub.f16.f16");
237 footprints["NEGH.i32"].push_back("f16.fneg.f16");
238 footprints["MULH.i32"].push_back("f16.fmul.f16.f16");
239 footprints["DIVH.i32"].push_back("f16.fdiv.f16.f16");
240 footprints["SQRTH.i32"].push_back("f16.sqrt.f16");
241
242 footprints["ADDF.i32"].push_back("f32.fadd.f32.f32");
243 footprints["SUBF.i32"].push_back("f32.fsub.f32.f32");
244 footprints["NEGF.i32"].push_back("f32.fneg.f32");
245 footprints["MULF.i32"].push_back("f32.fmul.f32.f32");
246 footprints["DIVF.i32"].push_back("f32.fdiv.f32.f32");
247 footprints["SQRTF.i32"].push_back("f32.sqrt.f32");
248
249 footprints["ADDD.i64"].push_back("f64.fadd.f64.f64");
250 footprints["SUBD.i64"].push_back("f64.fsub.f64.f64");
251 footprints["NEGD.i64"].push_back("f64.fneg.f64");
252 footprints["MULD.i64"].push_back("f64.fmul.f64.f64");
253 footprints["DIVD.i64"].push_back("f64.fdiv.f64.f64");
254 footprints["SQRTD.i64"].push_back("f64.sqrt.f64");
255
256 footprints["CFI.i32"].push_back("i32.fptosi.f32");
257 footprints["CFIU.i32"].push_back("i32.fptoui.f32");
258 footprints["CIF.i32"].push_back("f32.sitofp.i32");
259 footprints["CIFU.i32"].push_back("f32.uitofp.i32");
260
261 footprints["CFI.i16"].push_back("i16.fptosi.f32");
262 footprints["CFIU.i16"].push_back("i16.fptoui.f32");
263 footprints["CIF.i16"].push_back("f32.sitofp.i16");
264 footprints["CIFU.i16"].push_back("f32.uitofp.i16");
265
266 footprints["CFI.i8"].push_back("i8.fptosi.f32");
267 footprints["CFIU.i8"].push_back("i8.fptoui.f32");
268 footprints["CIF.i8"].push_back("f32.sitofp.i8");
269 footprints["CIFU.i8"].push_back("f32.uitofp.i8");
270
271 footprints["CDL.i64"].push_back("i64.fptosi.f64");
272 footprints["CDLU.i64"].push_back("i64.fptoui.f64");
273 footprints["CLD.i64"].push_back("f64.sitofp.i64");
274 footprints["CLDU.i64"].push_back("f64.uitofp.i64");
275
276 footprints["CDL.i32"].push_back("i32.fptosi.f64");
277 footprints["CDLU.i32"].push_back("i32.fptoui.f64");
278 footprints["CLD.i32"].push_back("f64.sitofp.i32");
279 footprints["CLDU.i32"].push_back("f64.uitofp.i32");
280
281 footprints["CDL.i16"].push_back("i16.fptosi.f64");
282 footprints["CDLU.i16"].push_back("i16.fptoui.f64");
283 footprints["CLD.i16"].push_back("f64.sitofp.i16");
284 footprints["CLDU.i16"].push_back("f64.uitofp.i16");
285
286 footprints["CDL.i8"].push_back("i8.fptosi.f64");
287 footprints["CDLU.i8"].push_back("i8.fptoui.f64");
288 footprints["CLD.i8"].push_back("f64.sitofp.i8");
289 footprints["CLDU.i8"].push_back("f64.uitofp.i8");
290
291 footprints["EQF.i1"].push_back("i1.fcmp.oeq.f32.f32");
292 footprints["NEF.i1"].push_back("i1.fcmp.one.f32.f32");
293 footprints["LTF.i1"].push_back("i1.fcmp.olt.f32.f32");
294 footprints["LEF.i1"].push_back("i1.fcmp.ole.f32.f32");
295 footprints["GTF.i1"].push_back("i1.fcmp.ogt.f32.f32");
296 footprints["GEF.i1"].push_back("i1.fcmp.oge.f32.f32");
297
298 footprints["EQUF.i1"].push_back("i1.fcmp.ueq.f32.f32");
299 footprints["NEUF.i1"].push_back("i1.fcmp.une.f32.f32");
300 footprints["LTUF.i1"].push_back("i1.fcmp.ult.f32.f32");
301 footprints["LEUF.i1"].push_back("i1.fcmp.ule.f32.f32");
302 footprints["GTUF.i1"].push_back("i1.fcmp.ugt.f32.f32");
303 footprints["GEUF.i1"].push_back("i1.fcmp.uge.f32.f32");
304
305 footprints["EQF.i32"].push_back("i32.fcmp.oeq.f32.f32");
306 footprints["NEF.i32"].push_back("i32.fcmp.one.f32.f32");
307 footprints["LTF.i32"].push_back("i32.fcmp.olt.f32.f32");
308 footprints["LEF.i32"].push_back("i32.fcmp.ole.f32.f32");
309 footprints["GTF.i32"].push_back("i32.fcmp.ogt.f32.f32");
310 footprints["GEF.i32"].push_back("i32.fcmp.oge.f32.f32");
311
312 footprints["EQUF.i32"].push_back("i32.fcmp.ueq.f32.f32");
313 footprints["NEUF.i32"].push_back("i32.fcmp.une.f32.f32");
314 footprints["LTUF.i32"].push_back("i32.fcmp.ult.f32.f32");
315 footprints["LEUF.i32"].push_back("i32.fcmp.ule.f32.f32");
316 footprints["GTUF.i32"].push_back("i32.fcmp.ugt.f32.f32");
317 footprints["GEUF.i32"].push_back("i32.fcmp.uge.f32.f32");
318
319 footprints["ORDF.i1"].push_back("i1.fcmp.ord.f32.f32");
320 footprints["ORDF.i32"].push_back("i32.fcmp.ord.f32.f32");
321 footprints["UORDF.i1"].push_back("i1.fcmp.uno.f32.f32");
322 footprints["UORDF.i32"].push_back("i32.fcmp.uno.f32.f32");
323
324 footprints["CFD.i64"].push_back("f64.fpext.f32");
325
326 footprints["EQD.i1"].push_back("i1.fcmp.oeq.f64.f64");
327 footprints["NED.i1"].push_back("i1.fcmp.one.f64.f64");
328 footprints["LTD.i1"].push_back("i1.fcmp.olt.f64.f64");
329 footprints["GED.i1"].push_back("i1.fcmp.oge.f64.f64");
330 footprints["LED.i1"].push_back("i1.fcmp.ole.f64.f64");
331 footprints["GTD.i1"].push_back("i1.fcmp.ogt.f64.f64");
332
333 footprints["EQD.i64"].push_back("i64.fcmp.oeq.f64.f64");
334 footprints["NED.i64"].push_back("i64.fcmp.one.f64.f64");
335 footprints["LTD.i64"].push_back("i64.fcmp.olt.f64.f64");
336 footprints["GED.i64"].push_back("i64.fcmp.oge.f64.f64");
337 footprints["LED.i64"].push_back("i64.fcmp.ole.f64.f64");
338 footprints["GTD.i64"].push_back("i64.fcmp.ogt.f64.f64");
339
340 footprints["EQUD.i1"].push_back("i1.fcmp.ueq.f64.f64");
341 footprints["NEUD.i1"].push_back("i1.fcmp.une.f64.f64");
342 footprints["GEUD.i1"].push_back("i1.fcmp.uge.f64.f64");
343 footprints["LEUD.i1"].push_back("i1.fcmp.ule.f64.f64");
344 footprints["LTUD.i1"].push_back("i1.fcmp.ult.f64.f64");
345 footprints["GTUD.i1"].push_back("i1.fcmp.ugt.f64.f64");
346
347 footprints["EQUD.i64"].push_back("i64.fcmp.ueq.f64.f64");
348 footprints["NEUD.i64"].push_back("i64.fcmp.une.f64.f64");
349 footprints["LEUD.i64"].push_back("i64.fcmp.ule.f64.f64");
350 footprints["GEUD.i64"].push_back("i64.fcmp.uge.f64.f64");
351 footprints["LTUD.i64"].push_back("i64.fcmp.ult.f64.f64");
352 footprints["GTUD.i64"].push_back("i64.fcmp.ugt.f64.f64");
353
354 footprints["ORDD.i1"].push_back("i1.fcmp.ord.f64.f64");
355 footprints["ORDD.i64"].push_back("i64.fcmp.ord.f64.f64");
356 footprints["UORDD.i1"].push_back("i1.fcmp.uno.f64.f64");
357 footprints["UORDD.i64"].push_back("i64.fcmp.uno.f64.f64");
358
359 init = false;
360 }
361
362 return footprints[tceOp];
363}
364
365std::string
366LowerMissingInstructions::getFootprint(Instruction& I) {
367
368 std::string footPrint = stringType(I.getType());
369
370 switch (I.getOpcode()) {
371
372 case Instruction::FCmp: {
373 FCmpInst* cmpInst = dyn_cast<FCmpInst>(&I);
374 footPrint += std::string(".") + cmpInst->getOpcodeName() + ".";
375
376 switch (cmpInst->getPredicate()) {
377 case FCmpInst::FCMP_FALSE:
378 footPrint += "false";
379 break;
380 case FCmpInst::FCMP_OEQ:
381 footPrint += "oeq";
382 break;
383 case FCmpInst::FCMP_OGT:
384 footPrint += "ogt";
385 break;
386 case FCmpInst::FCMP_OGE:
387 footPrint += "oge";
388 break;
389 case FCmpInst::FCMP_OLT:
390 footPrint += "olt";
391 break;
392 case FCmpInst::FCMP_OLE:
393 footPrint += "ole";
394 break;
395 case FCmpInst::FCMP_ONE:
396 footPrint += "one";
397 break;
398 case FCmpInst::FCMP_ORD:
399 footPrint += "ord";
400 break;
401 case FCmpInst::FCMP_UNO:
402 footPrint += "uno";
403 break;
404 case FCmpInst::FCMP_UEQ:
405 footPrint += "ueq";
406 break;
407 case FCmpInst::FCMP_UGT:
408 footPrint += "ugt";
409 break;
410 case FCmpInst::FCMP_UGE:
411 footPrint += "uge";
412 break;
413 case FCmpInst::FCMP_ULT:
414 footPrint += "ult";
415 break;
416 case FCmpInst::FCMP_ULE:
417 footPrint += "ule";
418 break;
419 case FCmpInst::FCMP_UNE:
420 footPrint += "une";
421 break;
422 case FCmpInst::FCMP_TRUE:
423 footPrint += "true";
424 break;
425 default:
426 footPrint += "PREDFAIL";
427 }
428 } break;
429
430 case Instruction::Call: {
431 if (!isa<CallInst>(&I) ||
432 dyn_cast<CallInst>(&I)->getCalledFunction() == NULL)
433 break;
434 std::string calledName =
435 dyn_cast<CallInst>(&I)->getCalledFunction()->getName().str();
436 if (calledName == "llvm.sqrt.f32") {
437 return "f32.sqrt.f32";
438 }
439
440 } break;
441
442 default:
443 footPrint += std::string(".") + I.getOpcodeName();
444 }
445
446 for (unsigned int i = 0; i < I.getNumOperands();i++) {
447 footPrint += "." + stringType(I.getOperand(i)->getType());
448 }
449
450 return footPrint;
451}
452
453void LowerMissingInstructions::addFunctionForFootprints(
454 Module& M, FunctionType* /*fType*/, Operation& op, std::string suffix) {
455
456 // set replace footprints for operations to emulate
457 // (there might be multiple different footprints for the same
458 // emulation function)
459 const std::vector<std::string>&
460 footprints = llvmFootprints(op.name() + suffix);
461
462 for (unsigned int j = 0; j < footprints.size(); j++) {
463 Function* func = M.getFunction(op.emulationFunctionName());
464 replaceFunctions[footprints[j]] = func;
465
466#if 0
467 std::cerr << "Operation: " << op.name()
468 << " is emulated with: " << op.emulationFunctionName()
469 << " footprint: " << footprints[j]
470 << std::endl;
471#endif
472 }
473}
474
475bool LowerMissingInstructions::doInitialization(Module &M) {
476
479 << std::endl
480 << "---- LowerMissingInstructions ----"
481 << std::endl;
482 }
483
484 dstModule_ = &M;
485
486 bool retVal = true;
487
489 opSet = MachineInfo::getOpset(*mach_);
490
492 requiredSet = LLVMBackend::llvmRequiredOpset(true, mach_->isLittleEndian(), mach_->is64bit());
493
494 OperationPool osal;
495
496 // Check required set, which must be lowered to function calls..
497 for (OperationDAGSelector::OperationSet::iterator i = requiredSet.begin();
498 i != requiredSet.end(); i++) {
499
500 if (opSet.find(*i) == opSet.end() &&
501 OperationDAGSelector::findDags(*i, opSet).empty()) {
502
503 Operation& op = osal.operation((*i).c_str());
504
505 if (&op == &NullOperation::instance()) {
506 std::cerr << "Error: Cant find operation: " << *i
507 << " from OSAL"
508 << std::endl;
509
510 return false;
511 }
512
513 if (op.numberOfOutputs() != 1) {
514 if (Application::verboseLevel() > 0) {
515 Application::errorStream() << "Cannot lower missing instruction:"
516 << *i << std::endl;
517 }
518 continue;
519 }
520
521 // Make parameter list for operation with all needed integer
522 // widths. If pure floating point just i32 is used.
523 //
524 // If there is also
525 // IntWord or UIntWord parameters all vectors are filled.
526 std::vector<ARGLIST_CONST Type*> argList_i64;
527 TYPE_CONST Type* retVal_i64 = NULL;
528
529 std::vector<ARGLIST_CONST Type*> argList_i32;
530 TYPE_CONST Type* retVal_i32 = NULL;
531
532 std::vector<ARGLIST_CONST Type*> argList_i16;
533 TYPE_CONST Type* retVal_i16 = NULL;
534
535 std::vector<ARGLIST_CONST Type*> argList_i8;
536 TYPE_CONST Type* retVal_i8 = NULL;
537
538 std::vector<ARGLIST_CONST Type*> argList_i1;
539 TYPE_CONST Type* retVal_i1 = NULL;
540
541 TYPE_CONST Type* defaultIntegerType =
542 mach_->is64bit() ?
543 Type::getInt64Ty(getGlobalContext()) :
544 Type::getInt32Ty(getGlobalContext());
545
546 std::vector<ARGLIST_CONST Type*>& argList_default =
547 mach_->is64bit() ? argList_i64 : argList_i32;
548
549 TYPE_CONST Type*& retVal_default =
550 mach_->is64bit() ? retVal_i64 : retVal_i32;
551
552 const char* defaultIntegerSuffix =
553 mach_->is64bit() ? ".i64" : ".i32";
554
555 bool useInt = false;
556 for (int j = 1; j <= op.numberOfInputs(); j++) {
557 Operand& operand = op.operand(j);
558 ARGLIST_CONST Type* llvmOp = getLLVMType(
559 operand.type(), //Type::getInt32Ty(getGlobalContext()));
560 defaultIntegerType);
561
562 argList_default.push_back(llvmOp);
563
564 if (llvmOp == defaultIntegerType) {
565 useInt = true;
566 }
567 }
568
569 Operand& outputOperand = op.operand(op.numberOfInputs() + 1);
570 retVal_default = getLLVMType(outputOperand.type(), defaultIntegerType);
571
572 // TODO: should also create smaller bit widths for long type operands??
573 if (retVal_default == defaultIntegerType) { //Type::getInt32Ty(getGlobalContext())) {
574 useInt = true;
575 }
576
577 FunctionType* fType_default =
578 FunctionType::get(retVal_default, argList_default, false);
579
580 if (retVal_default == Type::getInt32Ty(getGlobalContext()) ||
581 retVal_default == Type::getFloatTy(getGlobalContext())) {
582
583 FunctionType* fType_i32 =
584 FunctionType::get(Type::getInt32Ty(getGlobalContext()), argList_i32, false);
585 addFunctionForFootprints(M, fType_i32, op, ".i32"); //".i32");
586 } else {
587 addFunctionForFootprints(M, fType_default, op, defaultIntegerSuffix); //".i32");
588 }
589
590 // create other function protos for other integer bitwidths
591 if (useInt) {
592 if (retVal_default == defaultIntegerType) {
593 if (mach_->is64bit()) {
594 retVal_i32 = Type::getInt32Ty(getGlobalContext());
595 }
596 retVal_i16 = Type::getInt16Ty(getGlobalContext());
597 retVal_i8 = Type::getInt8Ty(getGlobalContext());
598 retVal_i1 = Type::getInt1Ty(getGlobalContext());
599 } else {
600 if (mach_->is64bit()) {
601 retVal_i32 = retVal_default;
602 }
603 retVal_i16 = retVal_default;
604 retVal_i8 = retVal_default;
605 retVal_i1 = retVal_default;
606 }
607
608 for (unsigned int j = 0; j < argList_default.size(); j++) {
609 ARGLIST_CONST Type* currArg = argList_default[j];
610 if (currArg == defaultIntegerType) {
611 if (mach_->is64bit()) {
612 argList_i32.push_back(Type::getInt32Ty(getGlobalContext()));
613 }
614 argList_i16.push_back(Type::getInt16Ty(getGlobalContext()));
615 argList_i8.push_back(Type::getInt8Ty(getGlobalContext()));
616 argList_i1.push_back(Type::getInt1Ty(getGlobalContext()));
617 } else {
618 if (mach_->is64bit()) {
619 argList_i16.push_back(currArg);
620 }
621 argList_i16.push_back(currArg);
622 argList_i8.push_back(currArg);
623 argList_i1.push_back(currArg);
624 }
625 }
626
627 if (mach_->is64bit()) {
628 FunctionType* fType_i32 =
629 FunctionType::get(retVal_i32, argList_i32, false);
630 addFunctionForFootprints(M, fType_i32, op, ".i32");
631 }
632
633 FunctionType* fType_i16 =
634 FunctionType::get(retVal_i16, argList_i16, false);
635
636 FunctionType* fType_i8 =
637 FunctionType::get(retVal_i8, argList_i8, false);
638
639 FunctionType* fType_i1 =
640 FunctionType::get(retVal_i1, argList_i1, false);
641
642 addFunctionForFootprints(M, fType_i16, op, ".i16");
643 addFunctionForFootprints(M, fType_i8, op, ".i8");
644 addFunctionForFootprints(M, fType_i1, op, ".i1");
645
646 }
647 }
648 }
649
650 return retVal;
651}
652
653bool LowerMissingInstructions::doFinalization(Module& /* M */) {
656 << std::endl
657 << "---- DONE: LowerMissingInstructions ----"
658 << std::endl;
659 }
660 return true;
661}
662
663// runOnBasicBlock - This method does the actual work of converting
664// instructions over, assuming that the pass has already been initialized.
665//
666bool LowerMissingInstructions::runOnBasicBlock(BasicBlock &BB) {
667 bool Changed = false;
668 #ifdef LLVM_OLDER_THAN_16
669 BasicBlock::InstListType &BBIL = BB.getInstList();
670 #endif
671
672 // Loop over all of the instructions, looking for instructions to lower
673 // instructions
674 for (BasicBlock::iterator I = BB.begin(), E = BB.end(); I != E; ++I) {
675
676 // get footprint of instruction
677 std::string footPrint = getFootprint(*I);
678
679 std::map<std::string, Function*>::iterator
680 replaceFunc = replaceFunctions.find(footPrint);
681
682 // std::cerr << "Footprint: " << footPrint << "\n";
683
684 if (replaceFunc != replaceFunctions.end()) {
685 if (replaceFunc->second == NULL) {
686 // this should leak down to llvm-tce
687 std::cerr
688 << (boost::format(
689 "ERROR: emulation function for footprint"
690 "'%s' wasn't found. Floating point"
691 " emulation required but --swfp was not given?") %
692 footPrint).str() << std::endl;
693 /* TODO: we have to exit() here as the Exception does not
694 propagate down to the llvm-tce with all distributions.
695 Should fail more gracefully as this is library code. */
696 exit(1);
697 }
701 << "Replacing: " << footPrint
702 << " with emulation function." << std::endl;
703 }
704 std::vector<Value*> args;
705
706 for (unsigned j = 0; j < I->getNumOperands(); j++) {
707
708 if (I->getOperand(j)->getType() == Type::getInt16Ty(getGlobalContext()) ||
709 I->getOperand(j)->getType() == Type::getInt8Ty(getGlobalContext()) ||
710 (I->getOperand(j)->getType() == Type::getInt32Ty(getGlobalContext()) &&
711 mach_->is64bit())) {
712
713 // Emulated operations with i1/i8/i16 operands need
714 // their operands extended to 32 bits. However, there's
715 // no easy way to see if the llvm operand requires
716 // sign or zero extension, so the correct extension is
717 // currently determined directly from the footprint.
718 if (footPrint == "f32.sitofp.i16" ||
719 footPrint == "f32.sitofp.i8") {
720
721 // sign extension needed
722 args.push_back(
723 llvm::CastInst::CreateIntegerCast(
724 I->getOperand(j),
725 Type::getInt32Ty(getGlobalContext()),
726 true, "", &(*I)));
727 } else if (footPrint == "f32.uitofp.i16" ||
728 footPrint == "f32.uitofp.i8") {
729 // zero extension needed
730 args.push_back(
731 llvm::CastInst::CreateIntegerCast(
732 I->getOperand(j),
733 Type::getInt32Ty(getGlobalContext()),
734 false, "", &(*I)));
735 } else if (footPrint == "f64.sitofp.i32" && mach_->is64bit()) {
736 args.push_back(
737 llvm::CastInst::CreateIntegerCast(
738 I->getOperand(j),
739 Type::getInt64Ty(getGlobalContext()),
740 true, "", &(*I)));
741
742 } else if (footPrint == "f64.uitofp.i32" && mach_->is64bit()) {
743 args.push_back(
744 llvm::CastInst::CreateIntegerCast(
745 I->getOperand(j),
746 Type::getInt64Ty(getGlobalContext()),
747 false, "", &(*I)));
748 } else {
749 // might not need ext after all.
750 args.push_back(I->getOperand(j));
751 }
752 } else if (I->getOpcode() == llvm::Instruction::Call
753 && j == 0) {
754 // the first operand of a Call is the called function pointer,
755 // ignore it
756 continue;
757 } else {
758 args.push_back(I->getOperand(j));
759 }
760 }
761 CallInst *NewCall =
762 CallInst::Create(
763 FunctionCallee(replaceFunc->second), args, Twine(""), &(*I));
764 NewCall->setTailCall();
765
766 // Replace all uses of the instruction with call instruction
767 if (I->getType() != NewCall->getType()) {
768
769 Value *MCast;
770 Instruction::CastOps castOps =
771 llvm::CastInst::getCastOpcode(
772 NewCall, false, I->getType(), false);
773 MCast = llvm::CastInst::Create(
774 castOps, NewCall, I->getType(), Twine(""),
775 &(*I));
776 I->replaceAllUsesWith(MCast);
777
778 } else {
779 I->replaceAllUsesWith(NewCall);
780 }
781
782 #ifdef LLVM_OLDER_THAN_16
783 I = --BBIL.erase(I);
784 #else
785 BB.erase(I, I);
786 #endif
787 Changed = true;
788
789 NumLowered++;
790 }
791 }
792 return Changed;
793}
794
795bool
796LowerMissingInstructions::runOnFunction(Function &F) {
797 for (BasicBlock &BB : F) {
798 runOnBasicBlock(BB);
799 }
800 return true;
801}
#define IGNORE_COMPILER_WARNING(X)
#define POP_COMPILER_DIAGS
const std::vector< std::string > & llvmFootprints(std::string tceOp)
STATISTIC(NumLowered, "Number of instructions lowered")
Pass * createLowerMissingInstructionsPass(const TTAMachine::Machine &mach)
#define ARGLIST_CONST
#define TYPE_CONST
static const int VERBOSE_LEVEL_DEFAULT
Default verbose level - do not print anything unnecessary.
static std::ostream & errorStream()
static int verboseLevel()
static std::ostream & logStream()
static OperationDAGSelector::OperationSet llvmRequiredOpset(bool includeFloatOps, bool isLittleEndian, bool bits64)
static OperationSet getOpset(const TTAMachine::Machine &mach)
static NullOperation & instance()
virtual OperandType type() const
Definition Operand.cc:165
OperandType
Definition Operand.hh:58
@ SLONG_WORD
Definition Operand.hh:66
@ FLOAT_WORD
Definition Operand.hh:61
@ ULONG_WORD
Definition Operand.hh:67
@ 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
TCETools::CIStringSet OperationSet
static OperationDAGList findDags(const std::string &opName, OperationSet opSet, const ImmInfo *immInfo=nullptr)
Operation & operation(const char *name)
virtual TCEString name() const
Definition Operation.cc:93
virtual int numberOfInputs() const
Definition Operation.cc:192
TCEString emulationFunctionName() const
Definition Operation.cc:623
virtual int numberOfOutputs() const
Definition Operation.cc:202
virtual Operand & operand(int id) const
Definition Operation.cc:541