From 905b0ce82cbb3e940ad96cafba29f5c0f0bcad2a Mon Sep 17 00:00:00 2001 From: Vlastimil Dort Date: Thu, 3 Dec 2015 10:58:10 +0100 Subject: [PATCH 1/5] Task 2 --- compiler.cpp | 3 +++ tests.cpp | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/compiler.cpp b/compiler.cpp index 606a455..bcc27b2 100644 --- a/compiler.cpp +++ b/compiler.cpp @@ -390,6 +390,9 @@ class Compiler : public Visitor { case ast::BinExp::Type::gt: result = RUNTIME_CALL(genericGt, lhs, rhs); return; + case ast::BinExp::Type::dot: + result = RUNTIME_CALL(genericDot, lhs, rhs); + return; default: // can't happen return; } diff --git a/tests.cpp b/tests.cpp index fe05cac..f339abd 100644 --- a/tests.cpp +++ b/tests.cpp @@ -222,7 +222,7 @@ namespace rift { TEST("a = \"aba\" a[c(0,2)]", "aa"); TEST("a = c(1,2,3) a[c(0,1)] = 56 a", 56, 56, 3); - // project2(); + project2(); // project3(); // project4(); // project5(); From e64386237d90083357a12695e551071dcc444bca Mon Sep 17 00:00:00 2001 From: Vlastimil Dort Date: Thu, 3 Dec 2015 11:09:31 +0100 Subject: [PATCH 2/5] Task 3 --- runtime.cpp | 12 ++++++++++-- tests.cpp | 2 +- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/runtime.cpp b/runtime.cpp index c1bdd1f..59595d8 100644 --- a/runtime.cpp +++ b/runtime.cpp @@ -526,11 +526,19 @@ RVal * c(int size, ...) { } double doubleDot(DoubleVector * lhs, DoubleVector * rhs) { - assert(false and "Fill me in"); + int productSize = max(lhs->size, rhs->size); + double result = 0; + for (int i = 0; i < productSize; ++i) + result += lhs->data[i % lhs->size] * rhs->data[i % rhs->size]; + return result; } RVal * genericDot(RVal * lhs, RVal * rhs) { - assert(false and "Fill me in"); + if (lhs->type != rhs->type) + throw "Incompatible types for dot product operator"; + if (lhs->type != RVal::Type::Double) + throw "Invalid types for dot product operator"; + return new RVal(new DoubleVector(doubleDot(lhs->d, rhs->d))); } diff --git a/tests.cpp b/tests.cpp index f339abd..8e36808 100644 --- a/tests.cpp +++ b/tests.cpp @@ -223,7 +223,7 @@ namespace rift { TEST("a = c(1,2,3) a[c(0,1)] = 56 a", 56, 56, 3); project2(); - // project3(); + project3(); // project4(); // project5(); // project6(); From b3040ba893a65a25c3b349e59c2189535da35725 Mon Sep 17 00:00:00 2001 From: Vlastimil Dort Date: Sat, 5 Dec 2015 20:35:45 +0100 Subject: [PATCH 3/5] Task 4 The genericDot always returns a single double. The analysis could be a bit more precise if bottom was returned when the call is guaranteed to fail. However, genericArithmetic does not do this. --- tests.cpp | 2 +- type_analysis.cpp | 7 ++++++- type_analysis.h | 1 + 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/tests.cpp b/tests.cpp index 8e36808..fa71e3f 100644 --- a/tests.cpp +++ b/tests.cpp @@ -224,7 +224,7 @@ namespace rift { project2(); project3(); - // project4(); + project4(); // project5(); // project6(); } diff --git a/type_analysis.cpp b/type_analysis.cpp index 136e3f7..2684189 100644 --- a/type_analysis.cpp +++ b/type_analysis.cpp @@ -14,7 +14,10 @@ char TypeAnalysis::ID = 0; AType * AType::top = createTop(); - +void TypeAnalysis::genericDot(CallInst * ci) { + // The result of the %*% operator is (if it succeeds) always a single scalar + state.update(ci, new AType(AType::Kind::R, AType::Kind::DV, AType::Kind::D)); +} void TypeAnalysis::genericArithmetic(CallInst * ci) { AType * lhs = state.get(ci->getOperand(0)); @@ -100,6 +103,8 @@ bool TypeAnalysis::runOnFunction(llvm::Function & f) { genericArithmetic(ci); } else if (s == "genericDiv") { genericArithmetic(ci); + } else if (s == "genericDot") { + genericDot(ci); } else if (s == "genericEq") { genericRelational(ci); } else if (s == "genericNeq") { diff --git a/type_analysis.h b/type_analysis.h index 79f3d7e..55cb23c 100644 --- a/type_analysis.h +++ b/type_analysis.h @@ -218,6 +218,7 @@ class TypeAnalysis : public llvm::FunctionPass { private: void genericArithmetic(llvm::CallInst * ci); + void genericDot(llvm::CallInst * ci); void genericRelational(llvm::CallInst * ci); void genericGetElement(llvm::CallInst * ci); From c8f310cf310fde1875af8a410791f7f5247b634f Mon Sep 17 00:00:00 2001 From: Vlastimil Dort Date: Sat, 5 Dec 2015 21:12:55 +0100 Subject: [PATCH 4/5] Task 5 --- tests.cpp | 2 +- unboxing.cpp | 18 ++++++++++++++++++ unboxing.h | 2 ++ 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/tests.cpp b/tests.cpp index fa71e3f..e72c9b3 100644 --- a/tests.cpp +++ b/tests.cpp @@ -225,7 +225,7 @@ namespace rift { project2(); project3(); project4(); - // project5(); + project5(); // project6(); } diff --git a/unboxing.cpp b/unboxing.cpp index 2b11f32..d3127a4 100644 --- a/unboxing.cpp +++ b/unboxing.cpp @@ -169,6 +169,22 @@ bool Unboxing::genericArithmetic(llvm::Instruction::BinaryOps op, llvm::Function } } +bool Unboxing::genericDot() { + AType * lhs = state().get(ins->getOperand(0)); + AType * rhs = state().get(ins->getOperand(1)); + if(lhs->isDouble() and rhs->isDouble()) { + // If both arguments are known to be vectors of double, + // we can unbox them. The result is then double scalar. + llvm::Value * l = getVectorPayload(lhs); + llvm::Value * r = getVectorPayload(rhs); + AType* result_t = updateAnalysis(RUNTIME_CALL(m->doubleDot, l, r), new AType(AType::Kind::D)); + ins->replaceAllUsesWith(box(result_t)); + return true; + } else { + return false; + } +} + void Unboxing::doubleRelational(AType * lhs, AType * rhs, llvm::CmpInst::Predicate op, llvm::Function * fop) { assert(lhs->isDouble() and rhs->isDouble() and "Doubles expected"); AType * result_t; @@ -337,6 +353,8 @@ bool Unboxing::runOnFunction(llvm::Function & f) { erase = genericArithmetic(Instruction::FMul, m->doubleMul); } else if (s == "genericDiv") { erase = genericArithmetic(Instruction::FDiv, m->doubleDiv); + } else if (s == "genericDot") { + erase = genericDot(); } else if (s == "genericLt") { erase = genericRelational(FCmpInst::FCMP_OLT, m->doubleLt); } else if (s == "genericGt") { diff --git a/unboxing.h b/unboxing.h index bb134c1..cf70169 100644 --- a/unboxing.h +++ b/unboxing.h @@ -48,6 +48,8 @@ class Unboxing : public llvm::FunctionPass { bool genericAdd(); + bool genericDot(); + bool genericArithmetic(llvm::Instruction::BinaryOps op, llvm::Function * fop); void doubleRelational(AType * lhs, AType * rhs, llvm::CmpInst::Predicate op, llvm::Function * fop); From b1594d2cc41c6e0761a12d558281bcd8b4279202 Mon Sep 17 00:00:00 2001 From: Vlastimil Dort Date: Sat, 5 Dec 2015 22:07:34 +0100 Subject: [PATCH 5/5] Task 6 --- tests.cpp | 2 +- unboxing.cpp | 16 +++++++++++++--- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/tests.cpp b/tests.cpp index e72c9b3..f347ccb 100644 --- a/tests.cpp +++ b/tests.cpp @@ -226,7 +226,7 @@ namespace rift { project3(); project4(); project5(); - // project6(); + project6(); } } // namespace rift diff --git a/unboxing.cpp b/unboxing.cpp index d3127a4..35ca9be 100644 --- a/unboxing.cpp +++ b/unboxing.cpp @@ -175,9 +175,19 @@ bool Unboxing::genericDot() { if(lhs->isDouble() and rhs->isDouble()) { // If both arguments are known to be vectors of double, // we can unbox them. The result is then double scalar. - llvm::Value * l = getVectorPayload(lhs); - llvm::Value * r = getVectorPayload(rhs); - AType* result_t = updateAnalysis(RUNTIME_CALL(m->doubleDot, l, r), new AType(AType::Kind::D)); + llvm::Value *l, *r, *result; + if(lhs->isScalar() and rhs->isScalar()) { + // If both arguments are scalar, use multiplication directly + l = getScalarPayload(lhs); + r = getScalarPayload(rhs); + result = BinaryOperator::Create(Instruction::FMul, l, r, "", ins); + } else { + // Otherwise use doubleDot function call + l = getVectorPayload(lhs); + r = getVectorPayload(rhs); + result = RUNTIME_CALL(m->doubleDot, l, r); + } + AType *result_t = updateAnalysis(result, new AType(AType::Kind::D)); ins->replaceAllUsesWith(box(result_t)); return true; } else {