|
79 | 79 | #include <unordered_map>
|
80 | 80 | #endif
|
81 | 81 |
|
82 |
| -#include <numeric> |
83 | 82 | #include <fstream>
|
| 83 | +#include <numeric> |
| 84 | +#include <thread> |
84 | 85 |
|
85 | 86 | #if defined(__i386__) || defined(__x86_64__)
|
86 | 87 | #include <xmmintrin.h>
|
@@ -117,6 +118,16 @@ namespace
|
117 | 118 |
|
118 | 119 | rr::MutexLock codegenMutex;
|
119 | 120 |
|
| 121 | + std::string replace(std::string str, const std::string& substr, const std::string& replacement) |
| 122 | + { |
| 123 | + size_t pos = 0; |
| 124 | + while((pos = str.find(substr, pos)) != std::string::npos) { |
| 125 | + str.replace(pos, substr.length(), replacement); |
| 126 | + pos += replacement.length(); |
| 127 | + } |
| 128 | + return str; |
| 129 | + } |
| 130 | + |
120 | 131 | #if REACTOR_LLVM_VERSION >= 7
|
121 | 132 | llvm::Value *lowerPAVG(llvm::Value *x, llvm::Value *y)
|
122 | 133 | {
|
@@ -538,12 +549,20 @@ namespace rr
|
538 | 549 | func_.emplace("floorf", reinterpret_cast<void*>(floorf));
|
539 | 550 | func_.emplace("nearbyintf", reinterpret_cast<void*>(nearbyintf));
|
540 | 551 | func_.emplace("truncf", reinterpret_cast<void*>(truncf));
|
| 552 | + func_.emplace("printf", reinterpret_cast<void*>(printf)); |
| 553 | + func_.emplace("puts", reinterpret_cast<void*>(puts)); |
541 | 554 | }
|
542 | 555 |
|
543 | 556 | void *findSymbol(const std::string &name) const
|
544 | 557 | {
|
545 |
| - FunctionMap::const_iterator it = func_.find(name); |
546 |
| - return (it != func_.end()) ? it->second : nullptr; |
| 558 | + // Trim off any underscores from the start of the symbol. LLVM likes |
| 559 | + // to append these on macOS. |
| 560 | + const char* trimmed = name.c_str(); |
| 561 | + while (trimmed[0] == '_') { trimmed++; } |
| 562 | + |
| 563 | + FunctionMap::const_iterator it = func_.find(trimmed); |
| 564 | + assert(it != func_.end()); // Missing functions will likely make the module fail in exciting non-obvious ways. |
| 565 | + return it->second; |
547 | 566 | }
|
548 | 567 | };
|
549 | 568 |
|
@@ -7512,4 +7531,97 @@ namespace rr
|
7512 | 7531 | }
|
7513 | 7532 | }
|
7514 | 7533 | #endif // defined(__i386__) || defined(__x86_64__)
|
| 7534 | + |
| 7535 | +#if ENABLE_RR_PRINT |
| 7536 | + // extractAll returns a vector containing the extracted n scalar value of |
| 7537 | + // the vector vec. |
| 7538 | + static std::vector<Value*> extractAll(Value* vec, int n) |
| 7539 | + { |
| 7540 | + std::vector<Value*> elements; |
| 7541 | + elements.reserve(n); |
| 7542 | + for (int i = 0; i < n; i++) |
| 7543 | + { |
| 7544 | + auto el = V(::builder->CreateExtractElement(V(vec), i)); |
| 7545 | + elements.push_back(el); |
| 7546 | + } |
| 7547 | + return elements; |
| 7548 | + } |
| 7549 | + |
| 7550 | + // toDouble returns all the float values in vals extended to doubles. |
| 7551 | + static std::vector<Value*> toDouble(const std::vector<Value*>& vals) |
| 7552 | + { |
| 7553 | + auto doubleTy = ::llvm::Type::getDoubleTy(*::context); |
| 7554 | + std::vector<Value*> elements; |
| 7555 | + elements.reserve(vals.size()); |
| 7556 | + for (auto v : vals) |
| 7557 | + { |
| 7558 | + elements.push_back(V(::builder->CreateFPExt(V(v), doubleTy))); |
| 7559 | + } |
| 7560 | + return elements; |
| 7561 | + } |
| 7562 | + |
| 7563 | + std::vector<Value*> PrintValue::Ty<Byte4>::val(const RValue<Byte4>& v) { return extractAll(v.value, 4); } |
| 7564 | + std::vector<Value*> PrintValue::Ty<Int4>::val(const RValue<Int4>& v) { return extractAll(v.value, 4); } |
| 7565 | + std::vector<Value*> PrintValue::Ty<UInt4>::val(const RValue<UInt4>& v) { return extractAll(v.value, 4); } |
| 7566 | + std::vector<Value*> PrintValue::Ty<Short4>::val(const RValue<Short4>& v) { return extractAll(v.value, 4); } |
| 7567 | + std::vector<Value*> PrintValue::Ty<UShort4>::val(const RValue<UShort4>& v) { return extractAll(v.value, 4); } |
| 7568 | + std::vector<Value*> PrintValue::Ty<Float>::val(const RValue<Float>& v) { return toDouble({v.value}); } |
| 7569 | + std::vector<Value*> PrintValue::Ty<Float4>::val(const RValue<Float4>& v) { return toDouble(extractAll(v.value, 4)); } |
| 7570 | + |
| 7571 | + void Printv(const char* function, const char* file, int line, const char* fmt, std::initializer_list<PrintValue> args) |
| 7572 | + { |
| 7573 | + // LLVM types used below. |
| 7574 | + auto i32Ty = ::llvm::Type::getInt32Ty(*::context); |
| 7575 | + auto intTy = ::llvm::Type::getInt64Ty(*::context); // TODO: Natural int width. |
| 7576 | + auto i8PtrTy = ::llvm::Type::getInt8PtrTy(*::context); |
| 7577 | + auto funcTy = ::llvm::FunctionType::get(i32Ty, {i8PtrTy}, true); |
| 7578 | + |
| 7579 | + auto func = ::module->getOrInsertFunction("printf", funcTy); |
| 7580 | + |
| 7581 | + // Build the printf format message string. |
| 7582 | + std::string str; |
| 7583 | + if (file != nullptr) { str += (line > 0) ? "%s:%d " : "%s "; } |
| 7584 | + if (function != nullptr) { str += "%s "; } |
| 7585 | + str += fmt; |
| 7586 | + |
| 7587 | + // Perform subsitution on all '{n}' bracketed indices in the format |
| 7588 | + // message. |
| 7589 | + int i = 0; |
| 7590 | + for (const PrintValue& arg : args) |
| 7591 | + { |
| 7592 | + str = replace(str, "{" + std::to_string(i++) + "}", arg.format); |
| 7593 | + } |
| 7594 | + |
| 7595 | + ::llvm::SmallVector<::llvm::Value*, 8> vals; |
| 7596 | + |
| 7597 | + // The format message is always the first argument. |
| 7598 | + vals.push_back(::builder->CreateGlobalStringPtr(str)); |
| 7599 | + |
| 7600 | + // Add optional file, line and function info if provided. |
| 7601 | + if (file != nullptr) |
| 7602 | + { |
| 7603 | + vals.push_back(::builder->CreateGlobalStringPtr(file)); |
| 7604 | + if (line > 0) |
| 7605 | + { |
| 7606 | + vals.push_back(::llvm::ConstantInt::get(intTy, line)); |
| 7607 | + } |
| 7608 | + } |
| 7609 | + if (function != nullptr) |
| 7610 | + { |
| 7611 | + vals.push_back(::builder->CreateGlobalStringPtr(function)); |
| 7612 | + } |
| 7613 | + |
| 7614 | + // Add all format arguments. |
| 7615 | + for (const PrintValue& arg : args) |
| 7616 | + { |
| 7617 | + for (auto val : arg.values) |
| 7618 | + { |
| 7619 | + vals.push_back(V(val)); |
| 7620 | + } |
| 7621 | + } |
| 7622 | + |
| 7623 | + ::builder->CreateCall(func, vals); |
| 7624 | + } |
| 7625 | +#endif // ENABLE_RR_PRINT |
| 7626 | + |
7515 | 7627 | }
|
0 commit comments