void TypeAnalysis::genericRelational(CallInst * ci) { AType * lhs = state.get(ci->getOperand(0)); AType * rhs = state.get(ci->getOperand(1)); if (lhs->isScalar() and rhs->isScalar()) { state.update(ci, new AType(AType::Kind::R, AType::Kind::DV, AType::Kind::D)); } else { state.update(ci, new AType(AType::Kind::R, AType::Kind::DV)); } }
void TypeAnalysis::genericGetElement(CallInst * ci) { AType * from = state.get(ci->getOperand(0)); AType * index = state.get(ci->getOperand(1)); if (from->isDouble()) { if (index->isScalar()) { state.update(ci, new AType(AType::Kind::R, AType::Kind::DV, AType::Kind::D)); } else { state.update(ci, new AType(AType::Kind::R, AType::Kind::DV)); } } else if (from->isCharacter()) { state.update(ci, new AType(AType::Kind::R, AType::Kind::CV)); } else { state.update(ci, new AType(AType::Kind::T)); } }
/** Checks that a dot operator result type is correctly set to be double scalar by the type analysis. */ void project4() { char const * source = "function(a, b) { a %*% b }"; try { Environment * env = new Environment(nullptr); RVal * actual = eval(env, source); llvm::Function * f = actual->f->bitcode; // run type analysis on the function //auto pm = llvm::legacy::FunctionPassManager(f->getParent()); TypeAnalysis ta; ta.runOnFunction(*f); // check the type of the genericDot intrinsic call for (auto & b : *f) { for (auto & i : b) { if (llvm::CallInst * ci = llvm::dyn_cast<llvm::CallInst>(&i)) { llvm::StringRef s = ci->getCalledFunction()->getName(); if (s == "genericDot") { AType * t = ta.state.get(ci); if (t->kind != AType::Kind::R or not t->isScalar()) throw "Generic dot does not have correct type"; if (ta.state.getLocation(t) != ci) throw "Location attached to the generic dot type is invalid"; t = t->payload; if (ta.state.getLocation(t) != nullptr) throw "Generic dot payload cannot have location"; t = t->payload; if (ta.state.getLocation(t) != nullptr) throw "Generic dot payload cannot have location"; return; } } } } throw "Generic dot not found"; } catch (char const * e) { cout << "ERROR at line " << __LINE__ << " : " << e << endl; cout << source << endl << endl; } catch (...) { cout << "ERROR at line " << __LINE__ << " : " << endl; cout << source << endl << endl; } }