From 927b7781d935f4953351e0436717bc3d124040a3 Mon Sep 17 00:00:00 2001 From: Josh Klontz Date: Mon, 31 Dec 2012 11:51:18 -0500 Subject: [PATCH] exposed jitcv Matrix class --- sdk/jitcv/jitcv.cpp | 1 + sdk/jitcv/jitcv.h | 88 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ sdk/plugins/llvm.cmake | 4 +++- sdk/plugins/llvm.cpp | 321 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------------------------------------------------------------------------------------------------------------------------------- sdk/plugins/plugins.cmake | 1 - 5 files changed, 268 insertions(+), 147 deletions(-) create mode 100644 sdk/jitcv/jitcv.cpp create mode 100644 sdk/jitcv/jitcv.h diff --git a/sdk/jitcv/jitcv.cpp b/sdk/jitcv/jitcv.cpp new file mode 100644 index 0000000..bd7600d --- /dev/null +++ b/sdk/jitcv/jitcv.cpp @@ -0,0 +1 @@ +#include "jitcv.h" diff --git a/sdk/jitcv/jitcv.h b/sdk/jitcv/jitcv.h new file mode 100644 index 0000000..9dfd366 --- /dev/null +++ b/sdk/jitcv/jitcv.h @@ -0,0 +1,88 @@ +#ifndef __JITCV_H +#define __JITCV_H + +#include +#include + +namespace jitcv +{ + +/*! + * \brief jitcv matrix + * \author Josh Klontz \cite jklontz + * \note Not part of the core SDK + */ +struct Matrix +{ + uint8_t *data; /*!< Data */ + uint32_t channels; /*!< Channels */ + uint32_t columns; /*!< Columns */ + uint32_t rows; /*!< Rows */ + uint32_t frames; /*!< Frames */ + uint16_t hash; /*!< Bits : 8 + Floating : 1 + Signed : 1 + (Reserved) : 2 + Single-channel : 1 + Single-column : 1 + Single-row : 1 + Single-frame : 1 */ + + enum Hash { Bits = 0x00FF, + Floating = 0x0100, + Signed = 0x0200, + SingleChannel = 0x1000, + SingleColumn = 0x2000, + SingleRow = 0x4000, + SingleFrame = 0x8000, + u1 = 1, + u8 = 8, + u16 = 16, + u32 = 32, + u64 = 64, + s8 = 8 + Signed, + s16 = 16 + Signed, + s32 = 32 + Signed, + s64 = 64 + Signed, + f16 = 16 + Floating + Signed, + f32 = 32 + Floating + Signed, + f64 = 64 + Floating + Signed }; + + Matrix() : data(NULL), channels(0), columns(0), rows(0), frames(0), hash(0) {} + + Matrix(uint32_t _channels, uint32_t _columns, uint32_t _rows, uint32_t _frames, uint16_t _hash) + : data(NULL), channels(_channels), columns(_columns), rows(_rows), frames(_frames), hash(_hash) + { + setSingleChannel(channels == 1); + setSingleColumn(columns == 1); + setSingleRow(rows == 1); + setSingleFrame(frames == 1); + } + + inline void copyHeader(const Matrix &other) { channels = other.channels; columns = other.columns; rows = other.rows; frames = other.frames; hash = other.hash; } + inline void allocate() { deallocate(); data = new uint8_t[bytes()]; } + inline void deallocate() { delete[] data; data = NULL; } + + inline int bits() const { return hash & Bits; } + inline void setBits(int bits) { hash &= ~Bits; hash |= bits & Bits; } + inline bool isFloating() const { return hash & Floating; } + inline void setFloating(bool isFloating) { isFloating ? setSigned(true), hash |= Floating : hash &= ~Floating; } + inline bool isSigned() const { return hash & Signed; } + inline void setSigned(bool isSigned) { isSigned ? hash |= Signed : hash &= ~Signed; } + inline int type() const { return hash & (Bits + Floating + Signed); } + inline void setType(int type) { hash &= ~(Bits + Floating + Signed); hash |= type & (Bits + Floating + Signed); } + inline bool singleChannel() const { return hash & SingleChannel; } + inline void setSingleChannel(bool singleChannel) { singleChannel ? hash |= SingleChannel : hash &= ~SingleChannel; } + inline bool singleColumn() const { return hash & SingleColumn; } + inline void setSingleColumn(bool singleColumn) { singleColumn ? hash |= SingleColumn : hash &= ~SingleColumn; } + inline bool singleRow() const { return hash & SingleRow; } + inline void setSingleRow(bool singleRow) { singleRow ? hash |= SingleRow : hash &= ~SingleRow; } + inline bool singleFrame() const { return hash & SingleFrame; } + inline void setSingleFrame(bool singleFrame) { singleFrame ? hash |= SingleFrame : hash &= ~SingleFrame; } + inline uint32_t elements() const { return channels * columns * rows * frames; } + inline uint32_t bytes() const { return bits() / 8 * elements(); } +}; + +} // namespace jitcv + +#endif // __JITCV_H diff --git a/sdk/plugins/llvm.cmake b/sdk/plugins/llvm.cmake index 237481c..e7be46d 100644 --- a/sdk/plugins/llvm.cmake +++ b/sdk/plugins/llvm.cmake @@ -21,6 +21,8 @@ if(${BR_WITH_LLVM}) # Let's suppose we want to build a JIT compiler with support for binary code: llvm_map_components_to_libraries(REQ_LLVM_LIBRARIES jit native) + set(BR_THIRDPARTY_SRC ${BR_THIRDPARTY_SRC} + ${CMAKE_SOURCE_DIR}/sdk/plugins/llvm.cpp + ${CMAKE_SOURCE_DIR}/sdk/jitcv/jitcv.cpp) set(BR_THIRDPARTY_LIBS ${BR_THIRDPARTY_LIBS} ${REQ_LLVM_LIBRARIES}) - set(BR_THIRDPARTY_SRC ${BR_THIRDPARTY_SRC} ${CMAKE_SOURCE_DIR}/sdk/plugins/llvm.cpp) endif() diff --git a/sdk/plugins/llvm.cpp b/sdk/plugins/llvm.cpp index 091ac44..d8ce1d8 100644 --- a/sdk/plugins/llvm.cpp +++ b/sdk/plugins/llvm.cpp @@ -21,9 +21,11 @@ #include #include "core/opencvutils.h" +#include "jitcv/jitcv.h" using namespace br; using namespace cv; +using namespace jitcv; using namespace llvm; static Module *TheModule = NULL; @@ -32,124 +34,59 @@ static FunctionPassManager *TheFunctionPassManager = NULL; static FunctionPassManager *TheExtraFunctionPassManager = NULL; static StructType *TheMatrixStruct = NULL; -/*! - * \brief LLVM matrix - * \author Josh Klontz \cite jklontz - * \note Not part of the core SDK - */ -struct Matrix +static QString MatrixToString(const Matrix &m) { - quint8 *data; /*!< Data */ - quint32 channels; /*!< Channels */ - quint32 columns; /*!< Columns */ - quint32 rows; /*!< Rows */ - quint32 frames; /*!< Frames */ - quint16 hash; /*!< Bits : 8 - Floating : 1 - Signed : 1 - Single-channel : 1 - Single-column : 1 - Single-row : 1 - Single-frame : 1 */ - - enum Hash { Bits = 0x00FF, - Floating = 0x0100, - Signed = 0x0200, - SingleChannel = 0x1000, - SingleColumn = 0x2000, - SingleRow = 0x4000, - SingleFrame = 0x8000, - u1 = 1, - u8 = 8, - u16 = 16, - u32 = 32, - u64 = 64, - s8 = 8 + Signed, - s16 = 16 + Signed, - s32 = 32 + Signed, - s64 = 64 + Signed, - f16 = 16 + Floating + Signed, - f32 = 32 + Floating + Signed, - f64 = 64 + Floating + Signed }; - - Matrix() : data(NULL), channels(0), columns(0), rows(0), frames(0), hash(0) {} - - Matrix(quint32 _channels, quint32 _columns, quint32 _rows, quint32 _frames, quint16 _hash) - : data(NULL), channels(_channels), columns(_columns), rows(_rows), frames(_frames), hash(_hash) - { - setSingleChannel(channels == 1); - setSingleColumn(columns == 1); - setSingleRow(rows == 1); - setSingleFrame(frames == 1); - } + return QString("%1%2%3%4%5%6%7").arg(QString::number(m.bits()), (m.isSigned() ? "s" : "u"), (m.isFloating() ? "f" : "i"), + QString::number(m.singleChannel()), QString::number(m.singleColumn()), QString::number(m.singleRow()), QString::number(m.singleFrame())); +} - Matrix(const cv::Mat &mat) - { - if (!mat.isContinuous()) qFatal("Matrix requires continuous data."); - channels = mat.channels(); - columns = mat.cols; - rows = mat.rows; - frames = 1; - - switch (mat.depth()) { - case CV_8U: hash = Matrix::u8; break; - case CV_8S: hash = Matrix::s8; break; - case CV_16U: hash = Matrix::u16; break; - case CV_16S: hash = Matrix::s16; break; - case CV_32S: hash = Matrix::s32; break; - case CV_32F: hash = Matrix::f32; break; - case CV_64F: hash = Matrix::f64; break; - default: qFatal("Unrecognized matrix depth."); - } +static Matrix MatrixFromMat(const cv::Mat &mat) +{ + Matrix m; + + if (!mat.isContinuous()) qFatal("Matrix requires continuous data."); + m.channels = mat.channels(); + m.columns = mat.cols; + m.rows = mat.rows; + m.frames = 1; + + switch (mat.depth()) { + case CV_8U: m.hash = Matrix::u8; break; + case CV_8S: m.hash = Matrix::s8; break; + case CV_16U: m.hash = Matrix::u16; break; + case CV_16S: m.hash = Matrix::s16; break; + case CV_32S: m.hash = Matrix::s32; break; + case CV_32F: m.hash = Matrix::f32; break; + case CV_64F: m.hash = Matrix::f64; break; + default: qFatal("Unrecognized matrix depth."); + } + + m.data = mat.data; + return m; +} - data = mat.data; - } - - void copyHeader(const Matrix &other) { channels = other.channels; columns = other.columns; rows = other.rows; frames = other.frames; hash = other.hash; } - void allocate() { deallocate(); data = new quint8[bytes()]; } - void allocate(Mat &m) { deallocate(); m = Mat(rows, columns, CV_MAKETYPE(getOpenCVDepth(), channels)); data = m.data; } - void deallocate() { delete[] data; data = NULL; } - - inline int bits() const { return hash & Bits; } - inline void setBits(int bits) { hash &= ~Bits; hash |= bits & Bits; } - inline bool isFloating() const { return hash & Floating; } - inline void setFloating(bool isFloating) { isFloating ? setSigned(true), hash |= Floating : hash &= ~Floating; } - inline bool isSigned() const { return hash & Signed; } - inline void setSigned(bool isSigned) { isSigned ? hash |= Signed : hash &= ~Signed; } - inline int type() const { return hash & (Bits + Floating + Signed); } - inline void setType(int type) { hash &= ~(Bits + Floating + Signed); hash |= type & (Bits + Floating + Signed); } - inline bool singleChannel() const { return hash & SingleChannel; } - inline void setSingleChannel(bool singleChannel) { singleChannel ? hash |= SingleChannel : hash &= ~SingleChannel; } - inline bool singleColumn() const { return hash & SingleColumn; } - inline void setSingleColumn(bool singleColumn) { singleColumn ? hash |= SingleColumn : hash &= ~SingleColumn; } - inline bool singleRow() const { return hash & SingleRow; } - inline void setSingleRow(bool singleRow) { singleRow ? hash |= SingleRow : hash &= ~SingleRow; } - inline bool singleFrame() const { return hash & SingleFrame; } - inline void setSingleFrame(bool singleFrame) { singleFrame ? hash |= SingleFrame : hash &= ~SingleFrame; } - inline quint32 elements() const { return channels * columns * rows * frames; } - inline quint32 bytes() const { return bits() / 8 * elements(); } - - QString toString() const { return QString("%1%2%3%4%5%6%7").arg(QString::number(bits()), (isSigned() ? "s" : "u"), (isFloating() ? "f" : "i"), - QString::number(singleChannel()), QString::number(singleColumn()), QString::number(singleRow()), QString::number(singleFrame())); } - - int getOpenCVDepth() const { - switch (type()) { - case u8: return CV_8U; - case s8: return CV_8S; - case u16: return CV_16U; - case s16: return CV_16S; - case s32: return CV_32S; - case f32: return CV_32F; - case f64: return CV_64F; - default: qFatal("OpenCV does not support Matrix format: %s", qPrintable(toString())); - } - return -1; - } -}; +static void AllocateMatrixFromMat(Matrix &m, cv::Mat &mat) +{ + int cvType = -1; + switch (m.type()) { + case Matrix::u8: cvType = CV_8U; break; + case Matrix::s8: cvType = CV_8S; break; + case Matrix::u16: cvType = CV_16U; break; + case Matrix::s16: cvType = CV_16S; break; + case Matrix::s32: cvType = CV_32S; break; + case Matrix::f32: cvType = CV_32F; break; + case Matrix::f64: cvType = CV_64F; break; + default: qFatal("OpenCV does not support Matrix format: %s", qPrintable(MatrixToString(m))); + } + + m.deallocate(); + mat = Mat(m.rows, m.columns, CV_MAKETYPE(cvType, m.channels)); + m.data = mat.data; +} QDebug operator<<(QDebug dbg, const Matrix &m) { - dbg.nospace() << m.toString(); + dbg.nospace() << MatrixToString(m); return dbg; } @@ -307,10 +244,10 @@ namespace br { /*! - * \brief LLVM Kernel + * \brief LLVM Unary Kernel * \author Josh Klontz \cite jklontz */ -class Kernel : public UntrainableMetaTransform +class UnaryKernel : public UntrainableMetaTransform { Q_OBJECT @@ -319,17 +256,18 @@ class Kernel : public UntrainableMetaTransform quint16 hash; public: - Kernel() : kernel(NULL), hash(0) {} + UnaryKernel() : kernel(NULL), hash(0) {} virtual int preallocate(const Matrix &src, Matrix &dst) const = 0; /*!< Preallocate destintation matrix based on source matrix. */ virtual void build(const MatrixBuilder &src, const MatrixBuilder &dst, PHINode *i) const = 0; /*!< Build the kernel. */ private: - QString mangledName(const Matrix &m) const { + QString mangledName(const Matrix &src) const + { static QHash argsLUT; const QString args = arguments().join(","); if (!argsLUT.contains(args)) argsLUT.insert(args, argsLUT.size()); int uid = argsLUT.value(args); - return "jitcv_" + name().remove("Transform") + QString::number(uid) + "_" + m.toString(); + return "jitcv_" + name().remove("Transform") + (args.isEmpty() ? QString() : QString::number(uid)) + "_" + MatrixToString(src); } Function *compile(const Matrix &m) const @@ -370,32 +308,125 @@ private: void project(const Template &src, Template &dst) const { - const Matrix m(src.m()); + const Matrix m(MatrixFromMat(src)); Matrix n; const int size = preallocate(m, n); - n.allocate(dst.m()); + AllocateMatrixFromMat(n, dst); + invoke(m, n, size); + } + + void invoke(const Matrix &src, Matrix &dst, int size) const + { + if (src.hash != hash) { + static QMutex compilerLock; + QMutexLocker locker(&compilerLock); + + if (src.hash != hash) { + const QString functionName = mangledName(src); + + Function *function = TheModule->getFunction(qPrintable(functionName)); + if (function == NULL) { + function = compile(src); + while (TheFunctionPassManager->run(*function)); + TheExtraFunctionPassManager->run(*function); + function = TheModule->getFunction(qPrintable(functionName)); + } + + const_cast(this)->kernel = (kernel_t)TheExecutionEngine->getPointerToFunction(function); + const_cast(this)->hash = src.hash; + } + } + + kernel(&src, &dst, size); + } +}; + +/*! + * \brief LLVM Binary Kernel + * \author Josh Klontz \cite jklontz + */ +class BinaryKernel: public UntrainableMetaTransform +{ + Q_OBJECT + + typedef void (*kernel_t)(const Matrix*, const Matrix*, Matrix*, quint32); + kernel_t kernel; + quint16 hashA, hashB; + +public: + BinaryKernel() : kernel(NULL), hashA(0), hashB(0) {} + virtual int preallocate(const Matrix &srcA, const Matrix &srcB, Matrix &dst) const = 0; /*!< Preallocate destintation matrix based on source matrix. */ + virtual void build(const MatrixBuilder &srcA, const MatrixBuilder &srcB, const MatrixBuilder &dst, PHINode *i) const = 0; /*!< Build the kernel. */ + +private: + QString mangledName(const Matrix &srcA, const Matrix &srcB) const + { + return "jitcv_" + name().remove("Transform") + "_" + MatrixToString(srcA) + "_" + MatrixToString(srcB); + } + + Function *compile(const Matrix &m, const Matrix &n) const + { + Constant *c = TheModule->getOrInsertFunction(qPrintable(mangledName(m, n)), + Type::getVoidTy(getGlobalContext()), + PointerType::getUnqual(TheMatrixStruct), + PointerType::getUnqual(TheMatrixStruct), + PointerType::getUnqual(TheMatrixStruct), + Type::getInt32Ty(getGlobalContext()), + NULL); + + Function *function = cast(c); + function->setCallingConv(CallingConv::C); - if (m.hash != hash) { + Function::arg_iterator args = function->arg_begin(); + Value *srcA = args++; + srcA->setName("srcA"); + Value *srcB = args++; + srcB->setName("srcB"); + Value *dst = args++; + dst->setName("dst"); + Value *len = args++; + len->setName("len"); + + BasicBlock *entry = BasicBlock::Create(getGlobalContext(), "entry", function); + IRBuilder<> builder(entry); + + BasicBlock *kernel; + PHINode *i = MatrixBuilder::beginLoop(builder, function, entry, &kernel, "i"); + + Matrix o; + preallocate(m, n, o); + build(MatrixBuilder(m, srcA, &builder, function, "srcA"), MatrixBuilder(n, srcB, &builder, function, "srcB"), MatrixBuilder(o, dst, &builder, function, "dst"), i); + + MatrixBuilder::endLoop(builder, function, kernel, i, len, "i"); + + builder.CreateRetVoid(); + return function; + } + + void invoke(const Matrix &srcA, const Matrix &srcB, Matrix &dst, int size) const + { + if ((srcA.hash != hashA) || (srcB.hash != hashB)) { static QMutex compilerLock; QMutexLocker locker(&compilerLock); - if (m.hash != hash) { - const QString functionName = mangledName(m); + if ((srcA.hash != hashA) || (srcB.hash != hashB)) { + const QString functionName = mangledName(srcA, srcB); Function *function = TheModule->getFunction(qPrintable(functionName)); if (function == NULL) { - function = compile(m); + function = compile(srcA, srcB); while (TheFunctionPassManager->run(*function)); TheExtraFunctionPassManager->run(*function); function = TheModule->getFunction(qPrintable(functionName)); } - const_cast(this)->kernel = (kernel_t)TheExecutionEngine->getPointerToFunction(function); - const_cast(this)->hash = m.hash; + const_cast(this)->kernel = (kernel_t)TheExecutionEngine->getPointerToFunction(function); + const_cast(this)->hashA = srcA.hash; + const_cast(this)->hashB = srcB.hash; } } - kernel(&m, &n, size); + kernel(&srcA, &srcB, &dst, size); } }; @@ -403,7 +434,7 @@ private: * \brief LLVM Stitchable Kernel * \author Josh Klontz \cite jklontz */ -class StitchableKernel : public Kernel +class StitchableKernel : public UnaryKernel { Q_OBJECT @@ -430,7 +461,7 @@ private: * \brief LLVM stitch transform * \author Josh Klontz \cite jklontz */ -class stitchTransform : public Kernel +class stitchTransform : public UnaryKernel { Q_OBJECT Q_PROPERTY(QList kernels READ get_kernels WRITE set_kernels RESET reset_kernels STORED false) @@ -447,7 +478,7 @@ class stitchTransform : public Kernel { Matrix tmp = src; foreach (const Transform *kernel, kernels) { - static_cast(kernel)->preallocate(tmp, dst); + static_cast(kernel)->preallocate(tmp, dst); tmp = dst; } return dst.elements(); @@ -459,7 +490,7 @@ class stitchTransform : public Kernel MatrixBuilder dst(dst_); Value *val = src.load(i); foreach (Transform *transform, kernels) { - static_cast(transform)->preallocate(src, dst); + static_cast(transform)->preallocate(src, dst); val = static_cast(transform)->stitch(src, dst, val); src.copyHeader(dst); src.m = dst.m; @@ -532,7 +563,7 @@ BR_REGISTER(Transform, powTransform) * \brief LLVM sum transform * \author Josh Klontz \cite jklontz */ -class sumTransform : public Kernel +class sumTransform : public UnaryKernel { Q_OBJECT Q_PROPERTY(bool channels READ get_channels WRITE set_channels RESET reset_channels STORED false) @@ -823,24 +854,24 @@ class LLVMInitializer : public Initializer Type::getInt16Ty(getGlobalContext()), // hash NULL); -// QSharedPointer kernel(Transform::make("abs", NULL)); + QSharedPointer kernel(Transform::make("abs", NULL)); -// Template src, dst; -// src.m() = (Mat_(2,2) << -1, -2, 3, 4); -// kernel->project(src, dst); -// qDebug() << dst.m(); + Template src, dst; + src.m() = (Mat_(2,2) << -1, -2, 3, 4); + kernel->project(src, dst); + qDebug() << dst.m(); -// src.m() = (Mat_(2,2) << -1, -3, 9, 27); -// kernel->project(src, dst); -// qDebug() << dst.m(); + src.m() = (Mat_(2,2) << -1, -3, 9, 27); + kernel->project(src, dst); + qDebug() << dst.m(); -// src.m() = (Mat_(2,2) << -1.5, -2.5, 3.5, 4.5); -// kernel->project(src, dst); -// qDebug() << dst.m(); + src.m() = (Mat_(2,2) << -1.5, -2.5, 3.5, 4.5); + kernel->project(src, dst); + qDebug() << dst.m(); -// src.m() = (Mat_(2,2) << 1.75, 2.75, -3.75, -4.75); -// kernel->project(src, dst); -// qDebug() << dst.m(); + src.m() = (Mat_(2,2) << 1.75, 2.75, -3.75, -4.75); + kernel->project(src, dst); + qDebug() << dst.m(); } void finalize() const diff --git a/sdk/plugins/plugins.cmake b/sdk/plugins/plugins.cmake index c198d5b..4672098 100644 --- a/sdk/plugins/plugins.cmake +++ b/sdk/plugins/plugins.cmake @@ -1,7 +1,6 @@ # Add source to BR_THIRDPARTY_SRC # Add libs to BR_THIRDPARTY_LIBS -include(ExternalProject) file(GLOB PLUGINS plugins/*.cpp) foreach(PLUGIN ${PLUGINS} ${BR_THIRDPARTY_PLUGINS}) get_filename_component(PLUGIN_BASENAME ${PLUGIN} NAME_WE) -- libgit2 0.21.4