2020-07-03 09:56:05 +08:00
|
|
|
//===- Algorith.cpp - Main algorithm --------------------------------------===//
|
|
|
|
//
|
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2020-07-05 07:40:02 +08:00
|
|
|
#include "npcomp/Typing/Analysis/CPA/Algorithm.h"
|
2020-07-03 09:56:05 +08:00
|
|
|
|
2020-07-06 07:09:16 +08:00
|
|
|
#include "mlir/IR/Diagnostics.h"
|
|
|
|
#include "llvm/Support/Debug.h"
|
|
|
|
|
|
|
|
#define DEBUG_TYPE "cpa-type-inference"
|
|
|
|
|
|
|
|
using namespace mlir;
|
2020-07-03 09:56:05 +08:00
|
|
|
using namespace mlir::NPCOMP::Typing::CPA;
|
|
|
|
|
2020-07-06 07:09:16 +08:00
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
// PropagationWorklist
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
2020-07-03 09:56:05 +08:00
|
|
|
PropagationWorklist::PropagationWorklist(Environment &env) : env(env) {
|
2020-07-04 04:29:52 +08:00
|
|
|
auto &contents = env.getConstraints();
|
2020-07-03 09:56:05 +08:00
|
|
|
currentConstraints.reserve(contents.size() * 2);
|
2020-07-04 04:29:52 +08:00
|
|
|
for (auto *c : contents) {
|
|
|
|
currentConstraints.insert(c);
|
2020-07-03 09:56:05 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool PropagationWorklist::commit() {
|
|
|
|
bool hadNew = newConstraintCount > 0;
|
|
|
|
newConstraintCount = 0;
|
|
|
|
return hadNew;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PropagationWorklist::propagateTransitivity() {
|
|
|
|
// Prepare for join.
|
|
|
|
constexpr size_t N = 8;
|
|
|
|
llvm::DenseMap<TypeVar *, llvm::SmallVector<ValueType *, N>> varToValueType;
|
2020-07-04 04:29:52 +08:00
|
|
|
llvm::DenseMap<TypeVar *, llvm::SmallVector<TypeNode *, N>> varToAny;
|
2020-07-03 09:56:05 +08:00
|
|
|
for (auto *c : currentConstraints) {
|
2020-07-04 04:29:52 +08:00
|
|
|
auto *lhsVar = llvm::dyn_cast<TypeVar>(c->getFrom());
|
|
|
|
auto *rhsVar = llvm::dyn_cast<TypeVar>(c->getTo());
|
2020-07-03 09:56:05 +08:00
|
|
|
|
|
|
|
if (lhsVar) {
|
2020-07-04 04:29:52 +08:00
|
|
|
varToAny[lhsVar].push_back(c->getTo());
|
2020-07-03 09:56:05 +08:00
|
|
|
}
|
|
|
|
if (rhsVar) {
|
2020-07-04 04:29:52 +08:00
|
|
|
if (auto *vt = llvm::dyn_cast<ValueType>(c->getFrom())) {
|
2020-07-03 09:56:05 +08:00
|
|
|
varToValueType[rhsVar].push_back(vt);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Expand join.
|
|
|
|
for (auto vtIt : varToValueType) {
|
|
|
|
auto &lhsSet = vtIt.second;
|
|
|
|
auto anyIt = varToAny.find(vtIt.first);
|
|
|
|
if (anyIt == varToAny.end())
|
|
|
|
continue;
|
|
|
|
auto &rhsSet = anyIt->second;
|
|
|
|
|
|
|
|
for (ValueType *lhsItem : lhsSet) {
|
2020-07-04 04:29:52 +08:00
|
|
|
for (TypeNode *rhsItem : rhsSet) {
|
2020-07-03 09:56:05 +08:00
|
|
|
Constraint *newC = env.getContext().getConstraint(lhsItem, rhsItem);
|
|
|
|
if (currentConstraints.insert(newC).second) {
|
2020-07-06 07:09:16 +08:00
|
|
|
LLVM_DEBUG(llvm::dbgs() << "-->ADD TRANS CONSTRAINT: ";
|
|
|
|
newC->print(env.getContext(), llvm::dbgs());
|
|
|
|
llvm::dbgs() << "\n";);
|
2020-07-03 09:56:05 +08:00
|
|
|
newConstraintCount += 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-07-06 07:09:16 +08:00
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
// GreedyTypeNodeVarResolver
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
ValueType *
|
|
|
|
GreedyTypeNodeVarResolver::unionCandidateTypes(const ValueTypeSet &candidates) {
|
|
|
|
if (candidates.empty()) {
|
|
|
|
mlir::emitOptionalError(loc, "no candidate types were identified");
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
if (candidates.size() != 1) {
|
|
|
|
mlir::emitOptionalError(loc, "ambiguous candidate types were identified");
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
return *candidates.begin();
|
|
|
|
}
|
|
|
|
|
|
|
|
LogicalResult GreedyTypeNodeVarResolver::analyzeTypeNode(TypeNode *tn) {
|
|
|
|
TypeVarSet newVars;
|
|
|
|
tn->collectDependentTypeVars(context, newVars);
|
|
|
|
if (newVars.empty())
|
|
|
|
return success();
|
|
|
|
|
|
|
|
// Breadth-first resolution of vars (that do not depend on other vars).
|
|
|
|
ValueTypeSet pendingValueTypes;
|
|
|
|
for (TypeVar *newTv : newVars) {
|
|
|
|
if (!allVars.insert(newTv).second)
|
|
|
|
continue;
|
|
|
|
if (mappings.count(newTv) == 1)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// Known mappings to this TypeVar.
|
|
|
|
auto &existingMembers = context.getMembers(newTv);
|
|
|
|
ValueTypeSet members(existingMembers.begin(), existingMembers.end());
|
|
|
|
|
|
|
|
ValueType *concreteVt = unionCandidateTypes(members);
|
|
|
|
if (!concreteVt)
|
|
|
|
return failure();
|
|
|
|
mappings[newTv] = concreteVt;
|
|
|
|
pendingValueTypes.insert(concreteVt);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Recursively analyze any newly discovered concrete types.
|
|
|
|
for (ValueType *nextValueType : pendingValueTypes) {
|
|
|
|
if (failed(analyzeTypeNode(nextValueType)))
|
|
|
|
return failure();
|
|
|
|
}
|
|
|
|
|
|
|
|
return success();
|
|
|
|
}
|