diff --git a/cudaBLAS/compileBatch.py b/cudaBLAS/compileBatch.py new file mode 100644 index 0000000..67edecd --- /dev/null +++ b/cudaBLAS/compileBatch.py @@ -0,0 +1,5 @@ +import os + +for n in [300,400,500,750,1000]: + filename = str(n) + ".cm" + os.system("./compile.sh " + filename) diff --git a/cudaBLAS/curvefit.py b/cudaBLAS/curvefit.py new file mode 100644 index 0000000..2982ab0 --- /dev/null +++ b/cudaBLAS/curvefit.py @@ -0,0 +1,18 @@ +from scipy.optimize import curve_fit +import numpy as np + +xdata = [70,80,90,100,110,120,130,140,150,160, +170,180,190,200,250,300,400,500,750,1000] + +ydata = [0.163639,0.230039,0.286963,0.343532,0.486311,0.511364,0.460507,0.604441,0.7165,0.789863,0.900274,0.968071,0.970639,1.072578,1.356337,1.740857,1.988335,2.903016,3.637857,4.235182] + + +def sigmoid(x, L ,x0, k, b): + y = L / (1 + np.exp(-k*(x-x0)))+b + return (y) + +p0 = [max(ydata), np.median(xdata),1,min(ydata)] # this is an mandatory initial guess + +popt, pcov = curve_fit(sigmoid, xdata, ydata) + +print(popt) diff --git a/cudaBLAS/generateLargeMatrix.py b/cudaBLAS/generateLargeMatrix.py new file mode 100644 index 0000000..366f7fe --- /dev/null +++ b/cudaBLAS/generateLargeMatrix.py @@ -0,0 +1,31 @@ +import numpy as np +import os + +def printAsCuMatMatrix(mat): + np.set_printoptions(threshold=9999999999) + file = "[" + file = file + np.array2string(mat, separator=', ').replace('],', '\\').replace('[', '').replace(']','') + file = file + ']' + return file + + +# for n in [300,400,500,750,1000]: +n = 10 +dim = (n,n) + +x = np.ones(dim) * 2.1 +# y = np.identity(dim[0]) * 1 + +programHeader = "func float[" + str(n) + "," + str(n) + "] main { a = " +programHeader = programHeader + printAsCuMatMatrix(x).replace("\n", "") +programHeader = programHeader + "\n" +programHeader = programHeader + "return a * a" +programHeader = programHeader + "}" +text_file = open("pythonoutput.cm", "w") + +text_file.write(programHeader) + +text_file.close() + +os.system("cp pythonoutput.cm ../cmake-build-debug/src/compiler/src/python.cm") +os.system("cp pythonoutput.cm ../cmake-build-debug/src/compiler/src/python.cm") \ No newline at end of file diff --git a/cudaBLAS/generateLargeMult.py b/cudaBLAS/generateLargeMult.py index efdd694..366f7fe 100644 --- a/cudaBLAS/generateLargeMult.py +++ b/cudaBLAS/generateLargeMult.py @@ -1,4 +1,5 @@ import numpy as np +import os def printAsCuMatMatrix(mat): np.set_printoptions(threshold=9999999999) @@ -7,19 +8,24 @@ def printAsCuMatMatrix(mat): file = file + ']' return file -n = 257 + +# for n in [300,400,500,750,1000]: +n = 10 dim = (n,n) x = np.ones(dim) * 2.1 # y = np.identity(dim[0]) * 1 -programHeader = "func int main { a = " +programHeader = "func float[" + str(n) + "," + str(n) + "] main { a = " programHeader = programHeader + printAsCuMatMatrix(x).replace("\n", "") programHeader = programHeader + "\n" -programHeader = programHeader + "return a .* a" +programHeader = programHeader + "return a * a" programHeader = programHeader + "}" text_file = open("pythonoutput.cm", "w") text_file.write(programHeader) -text_file.close() \ No newline at end of file +text_file.close() + +os.system("cp pythonoutput.cm ../cmake-build-debug/src/compiler/src/python.cm") +os.system("cp pythonoutput.cm ../cmake-build-debug/src/compiler/src/python.cm") \ No newline at end of file diff --git a/cudaBLAS/precompiled-cpu/10.cmProgram b/cudaBLAS/precompiled-cpu/10.cmProgram new file mode 100755 index 0000000..7bc3db5 Binary files /dev/null and b/cudaBLAS/precompiled-cpu/10.cmProgram differ diff --git a/cudaBLAS/precompiled-cpu/100.cmProgram b/cudaBLAS/precompiled-cpu/100.cmProgram new file mode 100755 index 0000000..ed3224e Binary files /dev/null and b/cudaBLAS/precompiled-cpu/100.cmProgram differ diff --git a/cudaBLAS/precompiled-cpu/1000.cmProgram b/cudaBLAS/precompiled-cpu/1000.cmProgram new file mode 100755 index 0000000..1b36869 Binary files /dev/null and b/cudaBLAS/precompiled-cpu/1000.cmProgram differ diff --git a/cudaBLAS/precompiled-cpu/150.cmProgram b/cudaBLAS/precompiled-cpu/150.cmProgram new file mode 100755 index 0000000..c67090a Binary files /dev/null and b/cudaBLAS/precompiled-cpu/150.cmProgram differ diff --git a/cudaBLAS/precompiled-cpu/2.cmProgram b/cudaBLAS/precompiled-cpu/2.cmProgram new file mode 100755 index 0000000..07e06ef Binary files /dev/null and b/cudaBLAS/precompiled-cpu/2.cmProgram differ diff --git a/cudaBLAS/precompiled-cpu/20.cmProgram b/cudaBLAS/precompiled-cpu/20.cmProgram new file mode 100755 index 0000000..3daeda8 Binary files /dev/null and b/cudaBLAS/precompiled-cpu/20.cmProgram differ diff --git a/cudaBLAS/precompiled-cpu/200.cmProgram b/cudaBLAS/precompiled-cpu/200.cmProgram new file mode 100755 index 0000000..ffc4ec8 Binary files /dev/null and b/cudaBLAS/precompiled-cpu/200.cmProgram differ diff --git a/cudaBLAS/precompiled-cpu/250.cmProgram b/cudaBLAS/precompiled-cpu/250.cmProgram new file mode 100755 index 0000000..fb44720 Binary files /dev/null and b/cudaBLAS/precompiled-cpu/250.cmProgram differ diff --git a/cudaBLAS/precompiled-cpu/300.cmProgram b/cudaBLAS/precompiled-cpu/300.cmProgram new file mode 100755 index 0000000..f5c3a0d Binary files /dev/null and b/cudaBLAS/precompiled-cpu/300.cmProgram differ diff --git a/cudaBLAS/precompiled-cpu/4.cmProgram b/cudaBLAS/precompiled-cpu/4.cmProgram new file mode 100755 index 0000000..c8a828f Binary files /dev/null and b/cudaBLAS/precompiled-cpu/4.cmProgram differ diff --git a/cudaBLAS/precompiled-cpu/40.cmProgram b/cudaBLAS/precompiled-cpu/40.cmProgram new file mode 100755 index 0000000..186321c Binary files /dev/null and b/cudaBLAS/precompiled-cpu/40.cmProgram differ diff --git a/cudaBLAS/precompiled-cpu/400.cmProgram b/cudaBLAS/precompiled-cpu/400.cmProgram new file mode 100755 index 0000000..57caa18 Binary files /dev/null and b/cudaBLAS/precompiled-cpu/400.cmProgram differ diff --git a/cudaBLAS/precompiled-cpu/500.cmProgram b/cudaBLAS/precompiled-cpu/500.cmProgram new file mode 100755 index 0000000..a7ad60f Binary files /dev/null and b/cudaBLAS/precompiled-cpu/500.cmProgram differ diff --git a/cudaBLAS/precompiled-cpu/6.cmProgram b/cudaBLAS/precompiled-cpu/6.cmProgram new file mode 100755 index 0000000..ad96421 Binary files /dev/null and b/cudaBLAS/precompiled-cpu/6.cmProgram differ diff --git a/cudaBLAS/precompiled-cpu/60.cmProgram b/cudaBLAS/precompiled-cpu/60.cmProgram new file mode 100755 index 0000000..8ea64b6 Binary files /dev/null and b/cudaBLAS/precompiled-cpu/60.cmProgram differ diff --git a/cudaBLAS/precompiled-cpu/750.cmProgram b/cudaBLAS/precompiled-cpu/750.cmProgram new file mode 100755 index 0000000..438b44b Binary files /dev/null and b/cudaBLAS/precompiled-cpu/750.cmProgram differ diff --git a/cudaBLAS/precompiled-cpu/8.cmProgram b/cudaBLAS/precompiled-cpu/8.cmProgram new file mode 100755 index 0000000..ab48016 Binary files /dev/null and b/cudaBLAS/precompiled-cpu/8.cmProgram differ diff --git a/cudaBLAS/precompiled-cpu/80.cmProgram b/cudaBLAS/precompiled-cpu/80.cmProgram new file mode 100755 index 0000000..c3e353d Binary files /dev/null and b/cudaBLAS/precompiled-cpu/80.cmProgram differ diff --git a/cudaBLAS/test b/cudaBLAS/test deleted file mode 100755 index ef6fead..0000000 Binary files a/cudaBLAS/test and /dev/null differ diff --git a/cudaBLAS/timer.py b/cudaBLAS/timer.py index f53d62d..6b0aa00 100644 --- a/cudaBLAS/timer.py +++ b/cudaBLAS/timer.py @@ -1,7 +1,15 @@ import time import os -start = time.perf_counter() -os.system("./CuMat-testBasic.cmProgram") -end = time.perf_counter() -print(end-start) \ No newline at end of file +# start = time.perf_counter() +# os.system("./CuMat-testBasic.cmProgram") +# end = time.perf_counter() +# print(end-start) +files = [2,4,6,8,10,20,40,60,80,100,150,200,250,300,400,500,750,1000] +for i in files: + filename = "./precompiled-cpu/" + str(i) + ".cmProgram" + start = time.perf_counter() + os.system(filename) + end = time.perf_counter() + timetaken = (end-start) * 1000 + print(f"Took: {timetaken}") \ No newline at end of file diff --git a/src/compiler/inc/CompilerOptions.hpp b/src/compiler/inc/CompilerOptions.hpp index b2bfbbb..80e7433 100644 --- a/src/compiler/inc/CompilerOptions.hpp +++ b/src/compiler/inc/CompilerOptions.hpp @@ -7,12 +7,16 @@ enum class WARNINGS { ALL, INFO, NONE }; enum class OPTIMISATION { NONE, ALL, EXPERIMENTAL }; +enum class COMPUTATION {AUTO, GPU, CPU}; + class CompilerOptions { public: WARNINGS warningVerbosity = WARNINGS::NONE; OPTIMISATION optimisationLevel = OPTIMISATION::ALL; + COMPUTATION computationMode = COMPUTATION::AUTO; + std::string inputFile; std::string outputFile; // Default to name of file diff --git a/src/compiler/src/main.cpp b/src/compiler/src/main.cpp index 689daa7..fdd462c 100644 --- a/src/compiler/src/main.cpp +++ b/src/compiler/src/main.cpp @@ -33,7 +33,7 @@ int main(int argc, char* argv[], char* envp[]) { std::string inputFileName; std::string outputFile; - const std::set validFlags = {"-Wall", "-Winfo", "-Wnone", "-Oall", "-Onone", "-Oexp", "-o", "-s"}; + const std::set validFlags = {"-Wall", "-Winfo", "-Wnone", "-Mauto", "-Mcpu", "-Mgpu", "-Oall", "-Onone", "-Oexp", "-o", "-s"}; // First argument is always name of exe, ignore for (int i = 1; i < argc; ++i) { @@ -95,6 +95,28 @@ int main(int argc, char* argv[], char* envp[]) { co.silent = true; } + // Assign GPU / CPU / Auto mode + std::vector compMode; + std::copy_if(args.begin(), args.end(), std::back_inserter(warningLevels), + [](std::string s) { return s.rfind("-M", 0) == 0; }); + if (warningLevels.size() > 1) { + printArgumentError("Maximum of one computation mode should be set", ""); + return 1; + } + if (warningLevels.size() == 1) { + auto warn = warningLevels.front(); + if (warn == "-Mgpu") { + co.computationMode = COMPUTATION::GPU; + } else if (warn == "-Mcpu") { + co.computationMode = COMPUTATION::CPU; + } else if (warn == "-Mauto") { + co.computationMode = COMPUTATION::AUTO; + } else { // This shouldn't happen, but for completeness + printArgumentError("Unrecognised computation level", warn); + return 1; // Quit early + } + } + // Assign Optimisation level std::vector optimiseLevels; std::copy_if(args.begin(), args.end(), std::back_inserter(optimiseLevels), diff --git a/src/parser/inc/DimensionPass.hpp b/src/parser/inc/DimensionPass.hpp index d4867e7..a44ed0e 100644 --- a/src/parser/inc/DimensionPass.hpp +++ b/src/parser/inc/DimensionPass.hpp @@ -8,4 +8,7 @@ #include "ASTNode.hpp" -void dimension_error(const std::string& message, AST::Node* node); \ No newline at end of file +void dimension_error(const std::string& message, AST::Node* node); +bool expandableDimensionMatrix(const Typing::MatrixType& left, const Typing::MatrixType& right); +bool expandableDimension(const Typing::Type& left, const Typing::Type& right); +std::vector expandedDimension(const Typing::MatrixType& left, const Typing::MatrixType& right); \ No newline at end of file diff --git a/src/parser/inc/ExprASTNode.hpp b/src/parser/inc/ExprASTNode.hpp index 4a81c4b..08d22a6 100644 --- a/src/parser/inc/ExprASTNode.hpp +++ b/src/parser/inc/ExprASTNode.hpp @@ -22,5 +22,6 @@ class ExprNode : public Node { std::shared_ptr& me) const { throw std::runtime_error("attempt to access constData on non-const node"); }; + [[nodiscard]] virtual bool isLiteralNode() const noexcept { return false; }; }; } // namespace AST diff --git a/src/parser/inc/LiteralNode.hpp b/src/parser/inc/LiteralNode.hpp index 83e0727..bd23e32 100644 --- a/src/parser/inc/LiteralNode.hpp +++ b/src/parser/inc/LiteralNode.hpp @@ -23,5 +23,7 @@ class LiteralNode : public ExprNode { std::shared_ptr& me) const override { return std::vector>{me}; } + + [[nodiscard]] bool isLiteralNode() const noexcept override { return true; }; }; } // namespace AST diff --git a/src/parser/inc/ProgramNode.hpp b/src/parser/inc/ProgramNode.hpp index 6f27111..b569530 100644 --- a/src/parser/inc/ProgramNode.hpp +++ b/src/parser/inc/ProgramNode.hpp @@ -6,7 +6,9 @@ namespace AST { class ProgramNode : public Node { public: llvm::Value* codeGen(Utils::IRContext* context) override; - [[nodiscard]] std::string toTree(const std::string& prefix, const std::string& childPrefix) const override{}; + [[nodiscard]] std::string toTree(const std::string& prefix, const std::string& childPrefix) const override { + return std::string{}; + }; void dimensionPass(Analysis::DimensionSymbolTable* nt) override; }; } // namespace AST \ No newline at end of file diff --git a/src/parser/inc/SliceNode.hpp b/src/parser/inc/SliceNode.hpp index f03247e..42e5b6e 100644 --- a/src/parser/inc/SliceNode.hpp +++ b/src/parser/inc/SliceNode.hpp @@ -12,6 +12,8 @@ class SliceNode : public Node { void semanticPass(Utils::IRContext* context) override; llvm::Value* codeGen(Utils::IRContext* context) override; - [[nodiscard]] std::string toTree(const std::string& prefix, const std::string& childPrefix) const override{}; + [[nodiscard]] std::string toTree(const std::string& prefix, const std::string& childPrefix) const override { + return std::string{}; + }; }; } // namespace AST \ No newline at end of file diff --git a/src/parser/inc/TernaryExprNode.hpp b/src/parser/inc/TernaryExprNode.hpp index 5433477..9903015 100644 --- a/src/parser/inc/TernaryExprNode.hpp +++ b/src/parser/inc/TernaryExprNode.hpp @@ -15,6 +15,8 @@ class TernaryExprNode : public ExprNode { void semanticPass(Utils::IRContext* context) override; llvm::Value* codeGen(Utils::IRContext* context) override; void dimensionPass(Analysis::DimensionSymbolTable* nt) override; - [[nodiscard]] std::string toTree(const std::string& prefix, const std::string& childPrefix) const override{}; + [[nodiscard]] std::string toTree(const std::string& prefix, const std::string& childPrefix) const override { + return std::string{}; + }; }; } // namespace AST \ No newline at end of file diff --git a/src/parser/inc/UnaryExprNode.hpp b/src/parser/inc/UnaryExprNode.hpp index 8d4e484..fc657e9 100644 --- a/src/parser/inc/UnaryExprNode.hpp +++ b/src/parser/inc/UnaryExprNode.hpp @@ -19,7 +19,9 @@ class UnaryExprNode : public ExprNode { llvm::Value* codeGen(Utils::IRContext* context) override; bool shouldExecuteGPU(Utils::IRContext* context, UNA_OPERATORS op); - [[nodiscard]] std::string toTree(const std::string& prefix, const std::string& childPrefix) const override{}; + [[nodiscard]] std::string toTree(const std::string& prefix, const std::string& childPrefix) const override { + return std::string{}; + }; void dimensionPass(Analysis::DimensionSymbolTable* nt) override; }; } // namespace AST \ No newline at end of file diff --git a/src/parser/inc/VariableNode.hpp b/src/parser/inc/VariableNode.hpp index a32a29e..822c83b 100644 --- a/src/parser/inc/VariableNode.hpp +++ b/src/parser/inc/VariableNode.hpp @@ -17,6 +17,8 @@ class VariableNode : public ExprNode { llvm::Value* codeGen(Utils::IRContext* context) override; llvm::Value* handleSlicing(Utils::IRContext* context, llvm::Value* val); - [[nodiscard]] std::string toTree(const std::string& prefix, const std::string& childPrefix) const override{}; + [[nodiscard]] std::string toTree(const std::string& prefix, const std::string& childPrefix) const override { + return std::string{}; + }; }; } // namespace AST \ No newline at end of file diff --git a/src/parser/samples/testBasic.cm b/src/parser/samples/testBasic.cm index 41f4200..1737838 100644 --- a/src/parser/samples/testBasic.cm +++ b/src/parser/samples/testBasic.cm @@ -1,3 +1,7 @@ -func int main { - return 1 + 2 +func int test(int[*] x) { + return if x == 1 then 2 else 3 +} + +func int[*] main { + return test (1) } \ No newline at end of file diff --git a/src/parser/src/ASTNode.cpp b/src/parser/src/ASTNode.cpp index aaa8756..cba48d2 100644 --- a/src/parser/src/ASTNode.cpp +++ b/src/parser/src/ASTNode.cpp @@ -36,4 +36,11 @@ std::string Node::toTree(const std::string& prefix, const std::string& childPref return str; } +void Node::dimensionPass(Analysis::DimensionSymbolTable* nt) { + for (auto const& child : this->children) child->dimensionPass(nt); +} +void Node::dimensionNamePass(Analysis::DimensionSymbolTable* nt) { + for (auto const& child : this->children) child->dimensionNamePass(nt); +} + } // namespace AST diff --git a/src/parser/src/AssignmentNode.cpp b/src/parser/src/AssignmentNode.cpp index d6dae27..af08aa0 100644 --- a/src/parser/src/AssignmentNode.cpp +++ b/src/parser/src/AssignmentNode.cpp @@ -13,7 +13,7 @@ llvm::Value* AST::AssignmentNode::codeGen(Utils::IRContext* context) { // Ensure that matrix literals are upcast if(auto* rValType = std::get_if(&*rVal->type)){ - if(rValType->rank == 0){ + if (this->rVal->isLiteralNode()) { rValLLVM = Utils::upcastLiteralToMatrix(context, *rValType, rValLLVM); } } @@ -112,13 +112,25 @@ llvm::Value* AST::AssignmentNode::decompAssign(Utils::IRContext* context, std::s auto matRecord = Utils::getMatrixFromPointer(context, matHeader); // Calculate offset of the rVal data address - llvm::Value* rValDataPtr = context->Builder->CreateGEP(matRecord.dataPtr, lValMatRecord.numBytes, "rValOffset"); + // llvm::Value* rValDataPtr = context->Builder->CreateGEP(matRecord.dataPtr, lValMatRecord.numBytes, + // "rValOffset"); // Point both of the data pointers to the correct locations - Utils::insertValueAtPointerOffset(context, lValMatRecord.dataPtr, 0, matRecord.dataPtr, false); - Utils::insertValueAtPointerOffset(context, rValMatRecord.dataPtr, 0, rValDataPtr, false); + auto* i32Ty = llvm::Type::getInt32Ty(context->module->getContext()); + auto dataPtr = Utils::getPointerAddressFromOffset(context, matRecord.dataPtr, llvm::ConstantInt::get(i32Ty, 0)); + auto secondDimDataPtr = Utils::getPointerAddressFromOffset(context, matRecord.dataPtr, + llvm::ConstantInt::get(i32Ty, matType->dimensions[0])); + llvm::Value* firstSize = llvm::ConstantExpr::getMul(llvm::ConstantInt::get(i32Ty, matType->dimensions[0]), + llvm::ConstantInt::get(i32Ty, 8)); + llvm::Value* secondSize = + llvm::ConstantExpr::getMul(llvm::ConstantExpr::getMul(llvm::ConstantInt::get(i32Ty, matType->dimensions[0]), + llvm::ConstantInt::get(i32Ty, matType->rank - 1)), + llvm::ConstantInt::get(i32Ty, 8)); + context->Builder->CreateMemCpy( + lValMatRecord.dataPtr, lValMatRecord.dataPtr->getPointerAlignment(context->module->getDataLayout()), dataPtr, + dataPtr->getPointerAlignment(context->module->getDataLayout()), firstSize); // Handle assignment symbol table code - if (!context->symbolTable->inSymbolTable(this->name, context->symbolTable->getCurrentFunction())) { + if (!context->symbolTable->inSymbolTable(decomp->lVal, context->symbolTable->getCurrentFunction())) { // Something has gone wrong during the parse stage and we have not added the symbol into the table // Raising a warning! if (context->compilerOptions->warningVerbosity == WARNINGS::ALL) { @@ -128,16 +140,16 @@ llvm::Value* AST::AssignmentNode::decompAssign(Utils::IRContext* context, std::s << std::endl; } // No typing information can be inferred at this stage (nullptr) - Can and will cause issues hence the warning - context->symbolTable->setValue(nullptr, lValMatAlloc, this->name, context->symbolTable->getCurrentFunction()); + context->symbolTable->setValue(nullptr, lValMatAlloc, decomp->lVal, context->symbolTable->getCurrentFunction()); } else { - context->symbolTable->updateValue(lValMatAlloc, this->name, context->symbolTable->getCurrentFunction()); + context->symbolTable->updateValue(lValMatAlloc, decomp->lVal, context->symbolTable->getCurrentFunction()); } // Handle any of the sub decompositions, these are not returned as we are not reducing the dimensions of them and we // only pick the first variable assigned, but they will be present within the symbol table - std::shared_ptr nestedDecomp = *std::get_if>(&decomp->rVal); - if (nestedDecomp) { - decompAssign(context, nestedDecomp, lValMatAlloc); + + if (auto nestedDecomp = std::get_if>(&decomp->rVal)) { + decompAssign(context, *nestedDecomp, lValMatAlloc); } return lValMatAlloc; // Dunno, seems to be what I would want, maybe change? } diff --git a/src/parser/src/BinaryExprNode.cpp b/src/parser/src/BinaryExprNode.cpp index 906311a..f951fc1 100644 --- a/src/parser/src/BinaryExprNode.cpp +++ b/src/parser/src/BinaryExprNode.cpp @@ -4,6 +4,7 @@ #include #include "CompilerOptions.hpp" +#include "DimensionPass.hpp" #include "TreePrint.hpp" #include "TypeCheckingUtils.hpp" @@ -23,12 +24,11 @@ llvm::Value* AST::BinaryExprNode::codeGen(Utils::IRContext* context) { if (auto* lhsType = std::get_if(&*lhsMatNode->type)) { if (auto* rhsType = std::get_if(&*rhsMatNode->type)) { - // Upcasting literal to matrix type - if(lhsType->rank == 0){ + if (lhsMatNode->isLiteralNode()) { lhsVal = Utils::upcastLiteralToMatrix(context, *lhsType, lhsVal); } - if(rhsType->rank == 0){ + if (rhsMatNode->isLiteralNode()) { rhsVal = Utils::upcastLiteralToMatrix(context, *rhsType, rhsVal); } @@ -42,12 +42,11 @@ llvm::Value* AST::BinaryExprNode::codeGen(Utils::IRContext* context) { newMatAlloc = Utils::createMatrix(context, *resType); - if (true || shouldExecuteGPU(context, op) || this->op == BIN_OPERATORS::MATM) { + if (shouldExecuteGPU(context, op) || this->op == BIN_OPERATORS::MATM) { if (this->op != BIN_OPERATORS::MATM) { llvm::Value* resLenLLVM = llvm::ConstantInt::get( llvm::Type::getInt64Ty(context->module->getContext()), resType->getLength()); - std::vector argVals( - {lhsVal, rhsVal,newMatAlloc, resLenLLVM}); + std::vector argVals({lhsVal, rhsVal, newMatAlloc, resLenLLVM}); if (lhsType->primType == Typing::PRIMITIVE::INT && rhsType->primType == Typing::PRIMITIVE::INT) { auto callRet = context->Builder->CreateCall( @@ -63,8 +62,7 @@ llvm::Value* AST::BinaryExprNode::codeGen(Utils::IRContext* context) { llvm::Value* lenK = llvm::ConstantInt::get(lenType, lhsType->dimensions[1]); llvm::Value* lenJ = llvm::ConstantInt::get(lenType, lhsType->dimensions[1]); - std::vector argVals( - {lhsVal, rhsVal,newMatAlloc, lenI, lenK, lenJ}); + std::vector argVals({lhsVal, rhsVal, newMatAlloc, lenI, lenK, lenJ}); if (lhsType->primType == Typing::PRIMITIVE::INT && rhsType->primType == Typing::PRIMITIVE::INT) { auto callRet = context->Builder->CreateCall( @@ -393,7 +391,7 @@ void AST::BinaryExprNode::semanticPass(Utils::IRContext* context) { case AST::BIN_OPERATORS::MINUS: case AST::BIN_OPERATORS::MUL: case AST::BIN_OPERATORS::DIV: - case AST::BIN_OPERATORS::MATM: // Dimensions sorted by Thomas later + case AST::BIN_OPERATORS::MATM: // Dimensions sorted by Thomas later TypeCheckUtils::assertNumericType(lhsPrim); TypeCheckUtils::assertNumericType(rhsPrim); primType = TypeCheckUtils::getHighestType(lhsPrim, rhsPrim); @@ -468,7 +466,9 @@ bool AST::BinaryExprNode::shouldExecuteGPU(Utils::IRContext* context, AST::BIN_O } entropy *= rhsType->getLength() * lhsType->getLength(); int maxCPUEntropy = 400; // 400 corresponds to 20x20 matrix - return entropy >= maxCPUEntropy; + bool entropyQuery = entropy >= maxCPUEntropy; + return (entropyQuery || context->compilerOptions->computationMode == COMPUTATION::GPU) && + (context->compilerOptions->computationMode != COMPUTATION::CPU); } /** @@ -621,4 +621,68 @@ std::string AST::BinaryExprNode::toTree(const std::string& prefix, const std::st str += rhs->toTree(childPrefix + L, childPrefix + B); return str; } + +void AST::BinaryExprNode::dimensionPass(Analysis::DimensionSymbolTable* nt) { + this->lhs->dimensionPass(nt); + this->rhs->dimensionPass(nt); + switch (this->op) { + case BIN_OPERATORS::PLUS: + case BIN_OPERATORS::MINUS: + case BIN_OPERATORS::MUL: + case BIN_OPERATORS::DIV: + case BIN_OPERATORS::LOR: + case BIN_OPERATORS::LAND: + case BIN_OPERATORS::LT: + case BIN_OPERATORS::GT: + case BIN_OPERATORS::LTE: + case BIN_OPERATORS::GTE: + case BIN_OPERATORS::EQ: + case BIN_OPERATORS::NEQ: + case BIN_OPERATORS::BAND: + case BIN_OPERATORS::BOR: + case BIN_OPERATORS::POW: + if (expandableDimension(*this->lhs->type, *this->rhs->type)) { + auto* t = std::get_if(&*this->type); + if (t) { + t->dimensions = expandedDimension(std::get(*this->lhs->type), + std::get(*this->rhs->type)); + t->rank = t->dimensions.size(); + } + } else { + auto* lType = std::get_if(this->lhs->type.get()); + auto* rType = std::get_if(this->rhs->type.get()); + if (lType && rType) { + std::string expected{"["}, actual{"["}; + for (auto i : lType->dimensions) expected.append(std::to_string(i) + ","); + expected.pop_back(); + expected.append("]"); + for (auto i : rType->dimensions) actual.append(std::to_string(i) + ","); + actual.pop_back(); + actual.append("]"); + dimension_error("Incompatible Binary Operator Dimensions", this); + } + } + break; + case BIN_OPERATORS::MATM: { + auto* t = std::get_if(&*this->type); + auto* l = std::get_if(this->lhs->type.get()); + auto* r = std::get_if(this->rhs->type.get()); + + if (t && l && r) { + if (l->rank != 2 || r->rank != 2) { + dimension_error("Matrix multiplication only defined on rank 2 variables", this); + } else { + if (l->dimensions[1] != r->dimensions[0]) { + dimension_error("Invalid matrix multiplication", this); + } + t->dimensions = {l->dimensions[0], r->dimensions[1]}; + t->rank = 2; + } + } + break; + } + case BIN_OPERATORS::CHAIN: + break; + } +} } // namespace AST \ No newline at end of file diff --git a/src/parser/src/BlockNode.cpp b/src/parser/src/BlockNode.cpp index 9b747df..a0069ae 100644 --- a/src/parser/src/BlockNode.cpp +++ b/src/parser/src/BlockNode.cpp @@ -16,35 +16,18 @@ llvm::Value* AST::BlockNode::codeGen(Utils::IRContext* context) { // Generate Return statement code llvm::Value* returnExprVal = this->returnExpr->codeGen(context); - if (this->callingFunctionName == "main") { - // lmao this is awful code deal with it - if (auto retType = std::get_if(&*this->returnExpr->type)) { - auto mainRecord = Utils::getMatrixFromPointer(context, returnExprVal); - llvm::Value* resLenLLVM = - llvm::ConstantInt::get(llvm::Type::getInt64Ty(context->module->getContext()), retType->getLength()); - std::vector argVals({mainRecord.dataPtr, resLenLLVM}); - - if (retType->primType == Typing::PRIMITIVE::INT) { - auto callRet = context->Builder->CreateCall(context->symbolTable->printFunctions.funcInt, argVals); - } else if (retType->primType == Typing::PRIMITIVE::FLOAT) { - auto callRet = context->Builder->CreateCall(context->symbolTable->printFunctions.funcFloat, argVals); - } else { - throw std::runtime_error("Main return type not valid"); - } - // Ensure that matrix literals are upcast - if (auto* rValType = std::get_if(&*returnExpr->type)) { - if (rValType->rank == 0) { - returnExprVal = Utils::upcastLiteralToMatrix(context, *rValType, returnExprVal); - } - } + // Ensure that matrix literals are upcast + if (auto* rValType = std::get_if(&*returnExpr->type)) { + if (returnExpr->isLiteralNode()) { + returnExprVal = Utils::upcastLiteralToMatrix(context, *rValType, returnExprVal); + } + } - printIfMainFunction(context, returnExprVal); + printIfMainFunction(context, returnExprVal); - llvm::Value* retVal = context->Builder->CreateRet(returnExprVal); + llvm::Value* retVal = context->Builder->CreateRet(returnExprVal); - return retVal; - } - } + return retVal; } void AST::BlockNode::semanticPass(Utils::IRContext* context) { @@ -69,7 +52,7 @@ std::string AST::BlockNode::toTree(const std::string& prefix, const std::string& * @param returnExprVal */ void AST::BlockNode::printIfMainFunction(Utils::IRContext* context, llvm::Value* returnExprVal) { - if (this->callingFunctionName == "main" && !context->compilerOptions->silent) { + if (this->callingFunctionName == "main") { // lmao this is awful code deal with it if (auto retType = std::get_if(&*this->returnExpr->type)) { std::vector argVals({returnExprVal}); diff --git a/src/parser/src/DecompNode.cpp b/src/parser/src/DecompNode.cpp index 10d72ab..2480f08 100644 --- a/src/parser/src/DecompNode.cpp +++ b/src/parser/src/DecompNode.cpp @@ -1,15 +1,12 @@ -#include -#include -#include -#include -#include - -#include "TypeCheckingUtils.hpp" #include "DecompNode.hpp" +#include +#include #include +#include #include "DimensionsSymbolTable.hpp" +#include "TypeCheckingUtils.hpp" llvm::Value* AST::DecompNode::codeGen(Utils::IRContext* context) { // if (auto variableName = std::get_if(&rVal)) { @@ -59,7 +56,8 @@ llvm::Value* AST::DecompNode::codeGen(Utils::IRContext* context) { void AST::DecompNode::semanticPass(Utils::IRContext* context, Typing::PRIMITIVE primType) { // Store a variable entry for the left hand string if (this->lVal != "_") { - context->semanticSymbolTable->storeVarType(this->lVal,TypeCheckUtils::makeMatrixType(std::vector(), primType)); + context->semanticSymbolTable->storeVarType(this->lVal, + TypeCheckUtils::makeMatrixType(std::vector(), primType)); } if (this->rVal.index() == 1) { // If a child decomp node exists, run semantic pass on it as well @@ -69,22 +67,30 @@ void AST::DecompNode::semanticPass(Utils::IRContext* context, Typing::PRIMITIVE // Else, store the rVal name as a variable std::string rValStr = std::get(this->rVal); if (rValStr != "_") { - context->semanticSymbolTable->storeVarType(rValStr,TypeCheckUtils::makeMatrixType(std::vector(), primType)); + context->semanticSymbolTable->storeVarType(rValStr, + TypeCheckUtils::makeMatrixType(std::vector(), primType)); } } } void AST::DecompNode::dimensionPass(Analysis::DimensionSymbolTable* nt, Typing::MatrixType& type) { Typing::MatrixType lType = type; Typing::MatrixType rType = type; - lType.rank--; - lType.dimensions.pop_back(); + + if (lType.rank <= 1) { + lType.rank = 1; + lType.dimensions[0] = 1; + } else { + lType.rank--; + lType.dimensions.pop_back(); + } + rType.dimensions.back()--; nt->add_node(this->lVal, std::move(std::make_shared(lType))); std::string* rName = std::get_if(&this->rVal); std::shared_ptr* rNode = std::get_if>(&this->rVal); if (rName) { - nt->add_node(this->lVal, std::move(std::make_shared(rType))); + nt->add_node(*rName, std::move(std::make_shared(rType))); } else if (rNode) { (*rNode)->dimensionPass(nt, rType); } diff --git a/src/parser/src/DimensionPass.cpp b/src/parser/src/DimensionPass.cpp index e9fb8fd..f5291a5 100644 --- a/src/parser/src/DimensionPass.cpp +++ b/src/parser/src/DimensionPass.cpp @@ -1,58 +1,10 @@ #include "DimensionPass.hpp" #include -#include #include #include #include -#include "Utils.hpp" - -bool expandableDimension(const Typing::Type& left, const Typing::Type& right); -std::vector expandedDimension(const Typing::MatrixType& left, const Typing::MatrixType& right); - -void AST::Node::dimensionPass(Analysis::DimensionSymbolTable* nt) { - for (auto const& child : this->children) child->dimensionPass(nt); -} -void AST::Node::dimensionNamePass(Analysis::DimensionSymbolTable* nt) { - for (auto const& child : this->children) child->dimensionNamePass(nt); -} - -void AST::BinaryExprNode::dimensionPass(Analysis::DimensionSymbolTable* nt) { - this->lhs->dimensionPass(nt); - this->rhs->dimensionPass(nt); - switch (this->op) { - case BIN_OPERATORS::PLUS: - case BIN_OPERATORS::MINUS: - case BIN_OPERATORS::MUL: - case BIN_OPERATORS::DIV: - case BIN_OPERATORS::LOR: - case BIN_OPERATORS::LAND: - case BIN_OPERATORS::LT: - case BIN_OPERATORS::GT: - case BIN_OPERATORS::LTE: - case BIN_OPERATORS::GTE: - case BIN_OPERATORS::EQ: - case BIN_OPERATORS::NEQ: - case BIN_OPERATORS::BAND: - case BIN_OPERATORS::BOR: - case BIN_OPERATORS::POW: - if (expandableDimension(*this->lhs->type, *this->rhs->type)) { - auto* t = std::get_if(&*this->type); - if (t) { - t->dimensions = expandedDimension(std::get(*this->lhs->type), - std::get(*this->rhs->type)); - } - } - break; - case BIN_OPERATORS::MATM: - // uses different dimensional rules... - break; - case BIN_OPERATORS::CHAIN: - break; - } -} - bool expandableDimensionMatrix(const Typing::MatrixType& left, const Typing::MatrixType& right) { const Typing::MatrixType* small; const Typing::MatrixType* big; @@ -64,10 +16,11 @@ bool expandableDimensionMatrix(const Typing::MatrixType& left, const Typing::Mat big = &right; } for (int i = 0; i < small->rank; i++) { - if (small->dimensions[i] && big->dimensions[i]) { + if (small->dimensions[i] != big->dimensions[i] && small->dimensions[i] != 0 && big->dimensions[i] != 0) { + return false; } } - return false; + return true; } bool expandableDimension(const Typing::Type& left, const Typing::Type& right) { diff --git a/src/parser/src/DimensionSymbolTable.cpp b/src/parser/src/DimensionSymbolTable.cpp index fbf1e2a..8e31381 100644 --- a/src/parser/src/DimensionSymbolTable.cpp +++ b/src/parser/src/DimensionSymbolTable.cpp @@ -1,4 +1,4 @@ -#include +#include #include "DimensionsSymbolTable.hpp" std::vector $tb_split(std::string_view str, char delim = '.'); diff --git a/src/parser/src/FuncDefNode.cpp b/src/parser/src/FuncDefNode.cpp index caca00a..2be4800 100644 --- a/src/parser/src/FuncDefNode.cpp +++ b/src/parser/src/FuncDefNode.cpp @@ -1,14 +1,13 @@ #include "FuncDefNode.hpp" -#include "TypeCheckingUtils.hpp" #include #include #include #include "DimensionPass.hpp" - #include "DimensionsSymbolTable.hpp" #include "TreePrint.hpp" +#include "TypeCheckingUtils.hpp" llvm::Value* AST::FuncDefNode::codeGen(Utils::IRContext* context) { // Let us generate a new function -> We will first generate the function argument types @@ -31,8 +30,9 @@ llvm::Value* AST::FuncDefNode::codeGen(Utils::IRContext* context) { // Add paramaters to the symbol table int i = 0; - for(auto funcitt = func->arg_begin(); funcitt != func->arg_end(); funcitt++, i++){ - context->symbolTable->setValue(this->parameters[i].second, (llvm::Value*) funcitt, this->parameters[i].first, funcName, ""); + for (auto funcitt = func->arg_begin(); funcitt != func->arg_end(); funcitt++, i++) { + context->symbolTable->setValue(this->parameters[i].second, (llvm::Value*)funcitt, this->parameters[i].first, + funcName, ""); } context->symbolTable->setFunctionData(funcName, typesRaw, func); @@ -48,7 +48,15 @@ llvm::Value* AST::FuncDefNode::codeGen(Utils::IRContext* context) { void AST::FuncDefNode::semanticPass(Utils::IRContext* context) { - // TODO: Put the args into symbol table temporarily for the block semantic pass - remove before end of function + // Check if the function name is already in use + if (context->semanticSymbolTable->inFuncTable(this->funcName, "")) { + TypeCheckUtils::alreadyDefinedError(this->funcName, false); + } + + auto ty = Typing::FunctionType(); + std::shared_ptr type = std::make_shared(ty); + context->semanticSymbolTable->storeFuncType(this->funcName, "", type); + std::vector> typesRaw; for (const auto& typeNamePair : this->parameters) { if ((typeNamePair.second.get())->index() == 0) { @@ -59,6 +67,11 @@ void AST::FuncDefNode::semanticPass(Utils::IRContext* context) { typesRaw.push_back(typeNamePair.second); } + auto typePtr = std::get_if(type.get()); + typePtr->parameters = typesRaw; + auto tempReturnType = TypeCheckUtils::makeMatrixType(std::vector{}, Typing::PRIMITIVE::NONE); + typePtr->returnType = tempReturnType; + // Store within the symbol table context->symbolTable->addNewFunction(funcName, typesRaw); @@ -72,16 +85,12 @@ void AST::FuncDefNode::semanticPass(Utils::IRContext* context) { std::exit(TypeCheckUtils::ErrorCodes::FUNCTION_ERROR); } + typePtr->returnType = this->returnType; + // Pop the function as we leave the definition of the code context->symbolTable->escapeFunction(); - // Check if the function name is already in use - if (context->semanticSymbolTable->inFuncTable(this->funcName, "")) { - TypeCheckUtils::alreadyDefinedError(this->funcName, false); - } // Construct the function type and store it - auto type = TypeCheckUtils::makeFunctionType(this->returnType, typesRaw); - context->semanticSymbolTable->storeFuncType(this->funcName, "", type); for (const auto& typeNamePair : this->parameters) { context->semanticSymbolTable->removeVarEntry(typeNamePair.first); } @@ -112,8 +121,17 @@ void AST::FuncDefNode::dimensionPass(Analysis::DimensionSymbolTable* nt) { auto* blocktype = std::get_if(this->block->returnExpr->type.get()); if (rettype && blocktype) { - if (rettype->dimensions == blocktype->dimensions) { - dimension_error("Return expression doesn't match declared signature", this); + if (!expandableDimensionMatrix(*rettype, *blocktype) || rettype->rank != blocktype->rank) { + std::string expected{"["}, actual{"["}; + for (auto i : rettype->dimensions) expected.append(std::to_string(i) + ","); + expected.pop_back(); + expected.append("]"); + for (auto i : blocktype->dimensions) actual.append(std::to_string(i) + ","); + actual.pop_back(); + actual.append("]"); + dimension_error(std::string{"Return expression doesn't match declared signature. Expected "} + expected + + ", got " + actual + ".", + this); } } } @@ -121,6 +139,15 @@ void AST::FuncDefNode::dimensionNamePass(Analysis::DimensionSymbolTable* nt) { if (auto a = std::get_if(this->returnType.get())) { if (a->dimensions.empty()) { a->dimensions.emplace_back(1); + a->rank = 1; + } + } + for (auto& [name, arg] : this->parameters) { + if (auto* a = std::get_if(arg.get())) { + if (a->dimensions.empty()) { + a->dimensions.emplace_back(1); + a->rank = 1; + } } } nt->add_node(this->funcName, this->returnType); diff --git a/src/parser/src/FunctionExprNode.cpp b/src/parser/src/FunctionExprNode.cpp index ade881b..e8c8aa7 100644 --- a/src/parser/src/FunctionExprNode.cpp +++ b/src/parser/src/FunctionExprNode.cpp @@ -38,7 +38,7 @@ llvm::Value* AST::FunctionExprNode::codeGen(Utils::IRContext* context) { llvm::Value* argVal = arg->codeGen(context); // Ensure that matrix literals are upcast if(auto* argType = std::get_if(&*arg->type)){ - if(argType->rank == 0){ + if (arg->isLiteralNode()) { argVal = Utils::upcastLiteralToMatrix(context, *argType, argVal); } } @@ -74,15 +74,29 @@ void AST::FunctionExprNode::semanticPass(Utils::IRContext* context) { // Get the argument types for the function std::vector> argTypes; - for (auto const& arg : this->args) { + for (auto& arg : this->args) { arg->semanticPass(context); - argTypes.push_back(std::move(arg->type)); + argTypes.push_back(arg->type); // Check that the argument type in this position matches the argument type in the function type - }; + } for (int i = 0; i < argTypes.size(); ++i) { - if (argTypes[i] != funcType->parameters[i]) { - std::cerr << "Function argument types do not match type definition" << std::endl; + auto argType = std::get_if(argTypes[i].get()); + + Typing::MatrixType* param; + if(i < funcType->parameters.size()) { + param = std::get_if(funcType->parameters[i].get()); + }else{ + std::cerr << "Invalid number of arguments supplied for " << nonAppliedFunc.name << "\n" + << "Expected: " << funcType->parameters.size() << "\n" + << "Found: " << argTypes.size(); + std::exit(TypeCheckUtils::ErrorCodes::FUNCTION_ERROR); + } + + if (argType->getPrimitiveType() != param->getPrimitiveType()) { + std::cerr << "Function argument types do not match type definition for " << nonAppliedFunc.name << "\n" + << "Expected: " << TypeCheckUtils::primToString(argType->getPrimitiveType()) << "\n" + << "Found: " << TypeCheckUtils::primToString(param->getPrimitiveType()) << std::endl; std::exit(TypeCheckUtils::ErrorCodes::FUNCTION_ERROR); } } @@ -111,8 +125,10 @@ void AST::FunctionExprNode::dimensionPass(Analysis::DimensionSymbolTable* nt) { for (auto& a : args) { a->dimensionPass(nt); } + if (std::holds_alternative(*nonAppliedFunction->type)) { - if (nt->search_impl(nonAppliedFunction->literalText)) { + if (auto func_type = nt->search_impl(nonAppliedFunction->literalText)) { + this->type = func_type; } } } diff --git a/src/parser/src/LiteralNode.cpp b/src/parser/src/LiteralNode.cpp index da7e755..3bf60c9 100644 --- a/src/parser/src/LiteralNode.cpp +++ b/src/parser/src/LiteralNode.cpp @@ -105,15 +105,18 @@ template <> std::string AST::LiteralNode::toTree(const std::string& prefix, const std::string& childPrefix) const { return prefix + std::to_string(value) + '\n'; } + template void AST::LiteralNode::dimensionPass(Analysis::DimensionSymbolTable* nt) { - if (Typing::MatrixType* mt = std::get_if(&*type)) { + Typing::MatrixType* mt = std::get_if(&*type); + if (mt) { mt->dimensions = std::vector{1}; mt->rank = 1; } else { throw std::runtime_error{"Invalid TypeClass for LiteralNode"}; } } + template <> std::string AST::LiteralNode::toTree(const std::string& prefix, const std::string& childPrefix) const { return prefix + std::to_string(value) + '\n'; diff --git a/src/parser/src/MatrixNode.cpp b/src/parser/src/MatrixNode.cpp index 3748b81..45ac905 100644 --- a/src/parser/src/MatrixNode.cpp +++ b/src/parser/src/MatrixNode.cpp @@ -54,7 +54,6 @@ llvm::Value* AST::MatrixNode::codeGen(Utils::IRContext* context) { // Compress literal nodes to matrix representation if (auto primType = std::get_if(&*this->type)) { llvm::Type* elType = primType->getLLVMPrimitiveType(context); - llvm::ArrayType* arrayType = llvm::ArrayType::get(elType, this->data.size()); std::vector values; for (int i = 0; i < this->data.size(); i++) { @@ -63,7 +62,7 @@ llvm::Value* AST::MatrixNode::codeGen(Utils::IRContext* context) { // Check if we can naively do this without causing recursive check -> Yes its not technically a matrix // Yes this violates our idea of every type being a matrix but its equivalent fuck it auto* literal = std::get_if(&*element->type); - if (literal->rank == 0) { + if (element->isLiteralNode()) { // Let's just generate code for the literal itself -> This returns a single value auto* elementLLVMMat = static_cast(element->codeGen(context)); values.push_back(elementLLVMMat); @@ -88,49 +87,30 @@ llvm::Value* AST::MatrixNode::codeGen(Utils::IRContext* context) { } } auto* i32Ty = llvm::Type::getInt32Ty(context->module->getContext()); - llvm::Constant* init = llvm::ConstantArray::get(arrayType, values); + int arraySize = 256*256 - 1000; + int numArrays = ((int) values.size() / arraySize) + 1; - auto * dataAllocSize = llvm::ConstantExpr::getTruncOrBitCast(llvm::ConstantExpr::getSizeOf(arrayType), i32Ty); - auto* arr = llvm::CallInst::CreateMalloc(context->Builder->GetInsertBlock(), i32Ty, arrayType, - dataAllocSize, nullptr, nullptr, ""); - context->Builder->Insert(arr, "matTmpData"); - context->Builder->CreateStore(init, arr); - context->Builder->CreateMemCpy( - matRecord.dataPtr, matRecord.dataPtr->getPointerAlignment(context->module->getDataLayout()), arr, - arr->getPointerAlignment(context->module->getDataLayout()), llvm::ConstantExpr::getSizeOf(arrayType)); - auto * freeMem = llvm::CallInst::CreateFree(arr, context->Builder->GetInsertBlock()); - context->Builder->Insert(freeMem); - // llvm::BasicBlock* addBB = - // llvm::BasicBlock::Create(context->Builder->getContext(), "matInitEntry", context->function); - // llvm::BasicBlock* endBB = llvm::BasicBlock::Create(context->Builder->getContext(), "matInitEnd"); - // - // auto indexAlloca = Utils::CreateEntryBlockAlloca(*context->Builder, "startIndex", - // llvm::Type::getInt32Ty(context->Builder->getContext())); - // llvm::Constant* matIndexEnd = llvm::ConstantInt::get(i32Ty, values.size()); - // // parent->getBasicBlockList().push_back(addBB); - // context->Builder->CreateBr(addBB); - // - // context->Builder->SetInsertPoint(addBB); - // { - // auto* index = context->Builder->CreateLoad(indexAlloca, "index"); - // - // llvm::Value* arrElement = Utils::getValueFromPointerOffsetValue(context, arr, index, - // "getArrConst"); Utils::insertValueAtPointerOffsetValue(context, matRecord.dataPtr, index, - // arrElement, false); - // - // // Update counter - // auto* next = context->Builder->CreateAdd( - // index, llvm::ConstantInt::get(context->module->getContext(), llvm::APInt{32, 1, true}), - // "inc"); - // context->Builder->CreateStore(next, indexAlloca); - // - // // Test if completed list - // auto* done = context->Builder->CreateICmpSGE(next, matIndexEnd); - // context->Builder->CreateCondBr(done, endBB, addBB); - // } - // - // context->function->getBasicBlockList().push_back(endBB); - // context->Builder->SetInsertPoint(endBB); + for(int i = 0; i < numArrays; i++){ + int arrayEnd = std::min(((i+1)* arraySize), (int)values.size()); + std::vector subArray = std::vector(values.begin()+(i*arraySize), values.begin()+ arrayEnd); + llvm::ArrayType* arrayType = llvm::ArrayType::get(elType, subArray.size()); + llvm::Constant* init = llvm::ConstantArray::get(arrayType, subArray); + auto * dataAllocSize = llvm::ConstantExpr::getTruncOrBitCast(llvm::ConstantExpr::getSizeOf(arrayType), i32Ty); + auto* arr = llvm::CallInst::CreateMalloc(context->Builder->GetInsertBlock(), i32Ty, arrayType, + dataAllocSize, nullptr, nullptr, ""); + context->Builder->Insert(arr, "matTmpData"); + context->Builder->CreateStore(init, arr); + + // Get a new dataptr + llvm::Value* offset = llvm::ConstantInt::get(i32Ty, (i*arraySize)); + llvm::Value* dataPtr = Utils::getPointerAddressFromOffset(context, matRecord.dataPtr, offset); + + context->Builder->CreateMemCpy( + dataPtr, dataPtr->getPointerAlignment(context->module->getDataLayout()), arr, + arr->getPointerAlignment(context->module->getDataLayout()), llvm::ConstantExpr::getSizeOf(arrayType)); + auto * freeMem = llvm::CallInst::CreateFree(arr, context->Builder->GetInsertBlock()); + context->Builder->Insert(freeMem); + } } return matAlloc; @@ -184,7 +164,7 @@ void AST::MatrixNode::semanticPass(Utils::IRContext* context) { } } - std::vector dimensions = this->getDimensions(); // Maybe use dimensions of inner matrix? + std::vector dimensions = this->getDimensions(); // Maybe use dimensions of inner matrix? this->type = TypeCheckUtils::makeMatrixType(dimensions, primType); } @@ -222,33 +202,40 @@ void AST::MatrixNode::dimensionPass(Analysis::DimensionSymbolTable* nt) { } std::vector apparent_dim{}; std::vector size{}; - - { - auto sep = this->separators.begin(); - for (int i = 0; i < this->data.size() - 1; i++) { - const auto& elem = data[i]; + if (separators.empty()) { + auto* type = std::get_if(&*this->type); + if (type) { + type->dimensions = {1}; + type->rank = 1; + } + } else { + { + auto sep = this->separators.begin(); + for (int i = 0; i < this->data.size() - 1; i++) { + const auto& elem = data[i]; + const auto* type = std::get_if(&*elem->type); + if (type) { + const auto& dims = type->dimensions; + dim_subpass(apparent_dim, size, dims, *(sep++)); + } + } + } + { + // have to do this separately as sep is one element shorter than data + const auto& elem = data[data.size() - 1]; const auto* type = std::get_if(&*elem->type); if (type) { const auto& dims = type->dimensions; - dim_subpass(apparent_dim, size, dims, *(sep++)); + dim_subpass(apparent_dim, size, dims, size.size()); } + apparent_dim.emplace_back(size.back()); } - } - { - // have to do this separately as sep is one element shorter than data - const auto& elem = data[data.size() - 1]; - const auto* type = std::get_if(&*elem->type); + + auto* type = std::get_if(&*this->type); if (type) { - const auto& dims = type->dimensions; - dim_subpass(apparent_dim, size, dims, size.size()); + type->dimensions = apparent_dim; + type->rank = apparent_dim.size(); } - apparent_dim.emplace_back(size.back()); - } - - auto* type = std::get_if(&*this->type); - if (type) { - type->dimensions = apparent_dim; - type->rank = apparent_dim.size(); } std::vector> new_vector{}; diff --git a/src/parser/src/SymbolTable.cpp b/src/parser/src/SymbolTable.cpp index deeceea..634ffdb 100644 --- a/src/parser/src/SymbolTable.cpp +++ b/src/parser/src/SymbolTable.cpp @@ -133,11 +133,11 @@ Utils::FunctionTableEntry Utils::SymbolTable::getFunction(const std::string& fun const std::vector>& params, const std::string& funcNamespace) { const std::string fullFuncName = funcNamespace + "::" + funcName; - if (!this->funcTable[fullFuncName].contains(params)) { - throw std::runtime_error("[Internal Error] Cannot retrieve function, not defined"); - } - auto trueParams = getFunctionTrueType(funcName, params, funcNamespace); - return this->funcTable[fullFuncName][trueParams]; +// if (!this->funcTable[fullFuncName].contains(params)) { +// throw std::runtime_error("[Internal Error] Cannot retrieve function, not defined"); +// } +// auto trueParams = getFunctionTrueType(funcName, params, funcNamespace); + return this->funcTable[fullFuncName].begin()->second; } /** diff --git a/src/parser/src/TernaryExprNode.cpp b/src/parser/src/TernaryExprNode.cpp index 67ae09d..0c2ff47 100644 --- a/src/parser/src/TernaryExprNode.cpp +++ b/src/parser/src/TernaryExprNode.cpp @@ -1,6 +1,7 @@ #include "TernaryExprNode.hpp" #include +#include #include "CodeGenUtils.hpp" #include "TypeCheckingUtils.hpp" @@ -55,19 +56,34 @@ void AST::TernaryExprNode::semanticPass(Utils::IRContext* context) { this->falsey->semanticPass(context); Typing::MatrixType tTy = TypeCheckUtils::extractMatrixType(this->truthy); Typing::MatrixType fTy = TypeCheckUtils::extractMatrixType(this->falsey); - TypeCheckUtils::assertMatchingTypes(tTy.getPrimitiveType(), fTy.getPrimitiveType()); - - this->type = TypeCheckUtils::makeMatrixType(std::vector(), tTy.getPrimitiveType()); + if (TypeCheckUtils::isNone(tTy.getPrimitiveType()) or TypeCheckUtils::isNone(fTy.getPrimitiveType())) { + if (TypeCheckUtils::isNone(tTy.getPrimitiveType()) and TypeCheckUtils::isNone(fTy.getPrimitiveType())) { + std::cerr << "Both branches of a Ternary Expression cannot be recursive calls" << std::endl; + std::exit(TypeCheckUtils::FUNCTION_ERROR); + } + if (TypeCheckUtils::isNone(tTy.getPrimitiveType())) { + this->type = TypeCheckUtils::makeMatrixType(std::vector(), fTy.getPrimitiveType()); + } else { + this->type = TypeCheckUtils::makeMatrixType(std::vector(), tTy.getPrimitiveType()); + } + } else { + TypeCheckUtils::assertMatchingTypes(tTy.getPrimitiveType(), fTy.getPrimitiveType()); + this->type = TypeCheckUtils::makeMatrixType(std::vector(), tTy.getPrimitiveType()); + } } + void AST::TernaryExprNode::dimensionPass(Analysis::DimensionSymbolTable* nt) { condition->dimensionPass(nt); truthy->dimensionPass(nt); falsey->dimensionPass(nt); auto* true_mt = std::get_if(&*truthy->type); auto* false_mt = std::get_if(&*falsey->type); - if (true_mt && false_mt) { - if (true_mt->dimensions != false_mt->dimensions) { + auto* type = std::get_if(this->type.get()); + if (true_mt && false_mt && type) { + if (!expandableDimensionMatrix(*true_mt, *false_mt) || true_mt->rank != false_mt->rank) { dimension_error("If else block branches yield miss-matched dimension", this); } + type->dimensions = expandedDimension(*true_mt, *false_mt); + type->rank = type->dimensions.size(); } } diff --git a/src/parser/src/TypeCheckingUtils.cpp b/src/parser/src/TypeCheckingUtils.cpp index 098b9a9..4ffd4a1 100644 --- a/src/parser/src/TypeCheckingUtils.cpp +++ b/src/parser/src/TypeCheckingUtils.cpp @@ -81,7 +81,7 @@ std::string TypeCheckUtils::primToString(Typing::PRIMITIVE ty) { } void TypeCheckUtils::wrongTypeError(std::string message, Typing::PRIMITIVE ty) { - std::cerr << "Wrong type encountered/n" << message << "/n" + std::cerr << "Wrong type encountered\n" << message << "\n" << "Found: " << primToString(ty) << std::endl; std::exit(TypeCheckUtils::ErrorCodes::WRONG_TYPE); } @@ -97,7 +97,7 @@ void TypeCheckUtils::noneError() { } void TypeCheckUtils::notDefinedError(std::string name) { - std::cerr << "Function with same name already defined: " << name << std::endl; + std::cerr << "No matching definition found: " << name << std::endl; std::exit(TypeCheckUtils::ErrorCodes::NOT_DEFINED_ERROR); } diff --git a/src/parser/src/UnaryExprNode.cpp b/src/parser/src/UnaryExprNode.cpp index 3bd853e..66f93d4 100644 --- a/src/parser/src/UnaryExprNode.cpp +++ b/src/parser/src/UnaryExprNode.cpp @@ -20,7 +20,7 @@ llvm::Value* AST::UnaryExprNode::codeGen(Utils::IRContext* context) { // Ensure that matrix literals are upcast if(auto* opType = std::get_if(&*this->operand->type)){ - if(opType->rank == 0){ + if (this->operand->isLiteralNode()) { operand = Utils::upcastLiteralToMatrix(context, *opType, operand); } } diff --git a/src/parser/src/VariableNode.cpp b/src/parser/src/VariableNode.cpp index d63f003..bb4848a 100644 --- a/src/parser/src/VariableNode.cpp +++ b/src/parser/src/VariableNode.cpp @@ -4,8 +4,8 @@ #include #include "CodeGenUtils.hpp" -#include "TypeCheckingUtils.hpp" #include "DimensionsSymbolTable.hpp" +#include "TypeCheckingUtils.hpp" llvm::Value* AST::VariableNode::codeGen(Utils::IRContext* context) { llvm::Value* storeVal = @@ -197,7 +197,6 @@ llvm::Value* AST::VariableNode::handleSlicing(Utils::IRContext* context, llvm::V return slicedMatrix; } - void AST::VariableNode::dimensionPass(Analysis::DimensionSymbolTable* nt) { auto p = nt->search_impl(name); auto* us = std::get_if(this->type.get()); @@ -205,5 +204,6 @@ void AST::VariableNode::dimensionPass(Analysis::DimensionSymbolTable* nt) { if (us && them) { // TODO do slicing (not tonight though...) us->dimensions = them->dimensions; + us->rank = them->rank; } }