- resolve duplicated code
- better connection
- divide long function
This commit is contained in:
Yutetsu TAKATSUKASA 2020-02-13 21:36:19 +09:00
parent 8e7366eab2
commit c498051c3d
No known key found for this signature in database
GPG Key ID: 8A1DD689B168385C
1 changed files with 152 additions and 116 deletions

View File

@ -221,14 +221,17 @@ public:
UnpackRef(AstNode* stmtp, AstSliceSel* nodep, int msb, int lsb, bool lvalue, bool ftask)
: m_context(stmtp)
, m_nodep(nodep)
, m_index(-1)
, m_index(msb == lsb ? msb : -1) // Equivalent to ArraySel
, m_msb(msb)
, m_lsb(lsb)
, m_lvalue(lvalue)
, m_ftask(ftask) {}
AstNode* nodep() const { return m_nodep; }
bool isSingleRef() const {
return VN_IS(m_nodep, ArraySel) || (m_msb == m_lsb && m_lsb == m_index);
}
int index() const {
UASSERT_OBJ(VN_IS(m_nodep, ArraySel), m_nodep, "not array sel");
UASSERT_OBJ(isSingleRef(), m_nodep, "not array sel");
return m_index;
}
AstNode* context() const { return m_context; }
@ -486,6 +489,13 @@ class SplitUnpackedVarVisitor : public AstNVisitor {
iterateChildren(nodep);
}
}
static AstNode* toInsertPoint(AstNode* insertp) {
if (AstNodeStmt* stmtp = VN_CAST(insertp, NodeStmt)) {
if (!stmtp->isStatement()) insertp = stmtp->backp();
}
if (AstVar* varp = VN_CAST(insertp, Var)) return toEndOfPort(varp);
return insertp;
}
AstVarRef* createTempVar(AstNode* context, AstNode* nodep, AstUnpackArrayDType* dtypep,
const std::string& name_prefix, std::vector<AstVar*>& vars,
int start_idx, bool lvalue, bool ftask) {
@ -511,10 +521,7 @@ class SplitUnpackedVarVisitor : public AstNVisitor {
if (!lvalue) std::swap(lhsp, rhsp);
AstNode* newassignp;
if (use_simple_assign) {
AstNode* insertp = context;
if (AstNodeStmt* stmtp = VN_CAST(insertp, NodeStmt)) {
if (!stmtp->isStatement()) insertp = stmtp->backp();
}
AstNode* insertp = toInsertPoint(context);
newassignp = new AstAssign(nodep->fileline(), lhsp, rhsp);
if (lvalue) { // If varp is LHS, this assignment must appear after the original assignment(context).
insertp->addNextHere(newassignp);
@ -531,8 +538,9 @@ class SplitUnpackedVarVisitor : public AstNVisitor {
}
return new AstVarRef(nodep->fileline(), varp, lvalue);
}
void connectPort(AstVar* varp, std::vector<AstVar*>& vars) {
void connectPort(AstVar* varp, std::vector<AstVar*>& vars, AstNode* insertp) {
UASSERT_OBJ(varp->isIO(), varp, "must be port");
insertp = insertp ? toInsertPoint(insertp) : NULL;
const bool lvalue = varp->direction().isWritable();
for (size_t i = 0; i < vars.size(); ++i) {
AstNode* nodes[] = {new AstArraySel(varp->fileline(),
@ -541,7 +549,16 @@ class SplitUnpackedVarVisitor : public AstNVisitor {
AstNode* lhsp = nodes[lvalue ? 0 : 1];
AstNode* rhsp = nodes[lvalue ? 1 : 0];
AstNodeAssign* assignp = newAssign(varp->fileline(), lhsp, rhsp, varp);
vars.at(i)->addNextHere(assignp);
if (insertp) {
if (lvalue) { // Just after writing to the temporary variable
insertp->addNextHere(assignp);
} else { // Just before reading the temporary variable
insertp->addHereThisAsNext(assignp);
}
} else {
UASSERT_OBJ(VN_IS(assignp, AssignW), varp, "must be AssginW");
vars.at(i)->addNextHere(assignp);
}
setContextAndIterate(assignp, nodes[1]);
}
}
@ -576,44 +593,39 @@ class SplitUnpackedVarVisitor : public AstNVisitor {
for (UnpackRefMap::SetIt sit = it->second.begin(), sit_end = it->second.end();
sit != sit_end; ++sit) {
AstNode* newp = NULL;
if (AstArraySel* selp = VN_CAST(sit->nodep(), ArraySel)) {
newp = new AstVarRef(selp->fileline(), vars.at(sit->index()), sit->lvalue());
} else if (AstVarRef* refp = VN_CAST(sit->nodep(), VarRef)) {
AstUnpackArrayDType* dtypep
= VN_CAST(refp->dtypep()->skipRefp(), UnpackArrayDType);
if (sit->isSingleRef()) {
newp = new AstVarRef(sit->nodep()->fileline(), vars.at(sit->index()), sit->lvalue());
} else {
AstVarRef* refp = VN_CAST(sit->nodep(), VarRef);
AstUnpackArrayDType* dtypep;
int lsb = 0;
if (refp) {
dtypep = VN_CAST(refp->dtypep()->skipRefp(), UnpackArrayDType);
} else {
AstSliceSel* selp = VN_CAST(sit->nodep(), SliceSel);
UASSERT_OBJ(selp, sit->nodep(), "Unexpected op is registered");
refp = VN_CAST(selp->fromp(), VarRef);
UASSERT_OBJ(refp, selp, "Unexpected op is registered");
dtypep = VN_CAST(selp->dtypep()->skipRefp(), UnpackArrayDType);
lsb = dtypep->lsb();
}
AstVarRef* newrefp = createTempVar(sit->context(), refp, dtypep, varp->name(),
vars, 0, refp->lvalue(), sit->ftask());
vars, lsb, refp->lvalue(), sit->ftask());
newp = newrefp;
toEndOfPort(refp->varp())->addNextHere(newrefp->varp());
UINFO(3,
"Create " << newrefp->varp()->prettyNameQ() << " for " << refp << "\n");
newp = newrefp;
} else if (AstSliceSel* selp = VN_CAST(sit->nodep(), SliceSel)) {
if (selp->declRange().elements() == 1) { // Just single element
UASSERT_OBJ(sit->range().first == sit->range().second, selp,
"must be a single element");
newp = new AstVarRef(selp->fileline(), vars.at(sit->range().first),
sit->lvalue());
} else { // Create a temp var
AstUnpackArrayDType* dtypep
= VN_CAST(selp->dtypep()->skipRefp(), UnpackArrayDType);
AstVarRef* refp = VN_CAST(selp->fromp(), VarRef);
AstVarRef* newrefp
= createTempVar(sit->context(), refp, dtypep, varp->name(), vars,
dtypep->lsb(), refp->lvalue(), sit->ftask());
toEndOfPort(refp->varp())->addNextHere(newrefp->varp());
UINFO(3, "Create " << newrefp->varp()->prettyNameQ() << " for " << selp
<< " of " << refp << "\n");
newp = newrefp;
}
} else {
UASSERT_OBJ(false, sit->nodep(), "Unexpected op is registered");
}
sit->nodep()->replaceWith(newp);
pushDeletep(sit->nodep());
setContextAndIterate(sit->context(), newp->backp());
// AstAssign is used. So assignment is necessary for each reference.
if (varp->isIO() && (varp->isFuncLocal() || varp->isFuncReturn()))
connectPort(varp, vars, sit->context());
}
if (varp->isIO()) {
connectPort(varp, vars);
if (!(varp->isFuncLocal() || varp->isFuncReturn())) // AssignW will be created, so just once
connectPort(varp, vars, NULL);
varp->attrSplitVar(!cannotSplitPackedVarReason(varp));
} else {
pushDeletep(varp->unlinkFrBack());
@ -898,14 +910,109 @@ class SplitPackedVarVisitor : public AstNVisitor {
return selp;
}
}
static void connectPortAndVar(const std::vector<SplitNewVar>& vars, AstVar* port) {
static void connectPortAndVar(const std::vector<SplitNewVar>& vars, AstVar* port, AstNode* insertp) {
for ( ; insertp; insertp = insertp->backp()) {
if (AstNodeStmt* stmtp = VN_CAST(insertp, NodeStmt)) {
if (stmtp->isStatement()) break;
}
}
const bool in = port->isReadOnly();
for (size_t i = 0; i < vars.size(); ++i) {
AstNode* rhs = new AstSel(port->fileline(), new AstVarRef(port->fileline(), port, !in),
vars[i].lsb(), vars[i].bitwidth());
AstNode* lhs = new AstVarRef(port->fileline(), vars[i].varp(), in);
if (!in) std::swap(lhs, rhs);
vars[i].varp()->addNextHere(newAssign(port->fileline(), lhs, rhs, port));
AstNodeAssign* assignp = newAssign(port->fileline(), lhs, rhs, port);
if (insertp) {
if (in)
insertp->addHereThisAsNext(assignp);
else
insertp->addNextHere(assignp);
} else {
vars[i].varp()->addNextHere(assignp);
}
}
}
void createVars(AstVar* varp, const AstBasicDType* basicp, std::vector<SplitNewVar>& vars) {
for (size_t i = 0; i < vars.size(); ++i) {
SplitNewVar* newvarp = &vars[i];
int left = newvarp->msb(), right = newvarp->lsb();
if (basicp->littleEndian()) std::swap(left, right);
const std::string name
= (left == right)
? varp->name() + "__BRA__" + AstNode::encodeNumber(left) + "__KET__"
: varp->name() + "__BRA__" + AstNode::encodeNumber(left)
+ AstNode::encodeName(":") + AstNode::encodeNumber(right)
+ "__KET__";
AstBasicDType* dtypep;
switch (basicp->keyword()) {
case AstBasicDTypeKwd::BIT:
dtypep = new AstBasicDType(varp->subDTypep()->fileline(), VFlagBitPacked(),
newvarp->bitwidth());
break;
case AstBasicDTypeKwd::LOGIC:
dtypep = new AstBasicDType(varp->subDTypep()->fileline(), VFlagLogicPacked(),
newvarp->bitwidth());
break;
default: UASSERT_OBJ(false, basicp, "Only bit and logic are allowed");
}
dtypep->rangep(new AstRange(varp->fileline(), newvarp->msb(), newvarp->lsb()));
dtypep->rangep()->littleEndian(basicp->littleEndian());
newvarp->varp(new AstVar(varp->fileline(), AstVarType::VAR, name, dtypep));
newvarp->varp()->propagateAttrFrom(varp);
newvarp->varp()->funcLocal(varp->isFuncLocal() || varp->isFuncReturn());
// newvarp->varp()->trace(varp->isTrace()); // Enable this line to trace split
// variable directly
m_netp->typeTablep()->addTypesp(dtypep);
varp->addNextHere(newvarp->varp());
UINFO(4, newvarp->varp()->prettyNameQ()
<< " is added for " << varp->prettyNameQ() << '\n');
}
}
static void updateReferences(AstVar* varp, PackedVarRef& ref, const std::vector<SplitNewVar> &vars) {
typedef std::vector<SplitNewVar> NewVars; // Sorted by its lsb
for (int lvalue = 0; lvalue <= 1; ++lvalue) { // Refer the new split variables
std::vector<PackedVarRefEntry>& refs = lvalue ? ref.lhs() : ref.rhs();
for (PackedVarRef::iterator refit = refs.begin(), refitend = refs.end();
refit != refitend; ++refit) {
NewVars::const_iterator varit = std::upper_bound(
vars.begin(), vars.end(), refit->lsb(), SplitNewVar::Match());
UASSERT_OBJ(varit != vars.end(), refit->nodep(), "Not found");
UASSERT(!(varit->msb() < refit->lsb() || refit->msb() < varit->lsb()),
"wrong search result");
AstNode* prev;
bool inSentitivityList = false;
if (AstSenItem* senitemp = refit->backSenItemp()) {
AstNode* oldsenrefp = senitemp->sensp();
oldsenrefp->replaceWith(new AstVarRef(senitemp->fileline(), varit->varp(), false));
VL_DO_DANGLING(oldsenrefp->deleteTree(), oldsenrefp);
prev = senitemp;
inSentitivityList = true;
} else {
prev = extractBits(*refit, *varit, lvalue);
}
for (int residue = refit->msb() - varit->msb(); residue > 0;
residue -= varit->bitwidth()) {
++varit;
UASSERT_OBJ(varit != vars.end(), refit->nodep(),
"not enough split variables");
if (AstSenItem* senitemp = VN_CAST(prev, SenItem)) {
prev = new AstSenItem(senitemp->fileline(), senitemp->edgeType(),
new AstVarRef(senitemp->fileline(), varit->varp(), false));
senitemp->addNextHere(prev);
} else {
AstNode* bitsp = extractBits(*refit, *varit, lvalue);
prev = new AstConcat(refit->nodep()->fileline(), bitsp, prev);
}
}
// If varp is an argument of task/func, need to update temporary var
// everytime the var is updated. See also another call of connectPortAndVar() in split().
if (varp->isIO() && (varp->isFuncLocal() || varp->isFuncReturn()))
connectPortAndVar(vars, varp, refit->nodep());
if (!inSentitivityList) refit->replaceNodeWith(prev);
UASSERT_OBJ(varit->msb() >= refit->msb(), varit->varp(), "Out of range");
}
}
}
// The actual splitting operation is done in this function.
@ -914,94 +1021,23 @@ class SplitPackedVarVisitor : public AstNVisitor {
it_end = m_refs.end();
it != it_end; ++it) {
AstVar* varp = it->first;
const AstBasicDType* basicp = it->second.basicp();
UINFO(3, "In module " << m_modp->name() << " var " << varp->prettyNameQ()
<< " which has " << it->second.lhs().size() << " lhs refs and "
<< it->second.rhs().size() << " rhs refs will be split.\n");
typedef std::vector<SplitNewVar> NewVars; // Sorted by its lsb
NewVars vars
std::vector<SplitNewVar> vars
= it->second.splitPlan(!varp->isTrace()); // If traced, all bit must be kept
if (vars.empty()) continue;
if (vars.size() == 1 && vars.front().bitwidth() == varp->width())
continue; // No split
// Add the split variables
for (size_t i = 0; i < vars.size(); ++i) {
SplitNewVar* newvarp = &vars[i];
int left = newvarp->msb(), right = newvarp->lsb();
if (basicp->littleEndian()) std::swap(left, right);
const std::string name
= (left == right)
? varp->name() + "__BRA__" + AstNode::encodeNumber(left) + "__KET__"
: varp->name() + "__BRA__" + AstNode::encodeNumber(left)
+ AstNode::encodeName(":") + AstNode::encodeNumber(right)
+ "__KET__";
AstBasicDType* dtypep;
switch (basicp->keyword()) {
case AstBasicDTypeKwd::BIT:
dtypep = new AstBasicDType(varp->subDTypep()->fileline(), VFlagBitPacked(),
newvarp->bitwidth());
break;
case AstBasicDTypeKwd::LOGIC:
dtypep = new AstBasicDType(varp->subDTypep()->fileline(), VFlagLogicPacked(),
newvarp->bitwidth());
break;
default: UASSERT_OBJ(false, basicp, "Only bit and logic are allowed");
}
dtypep->rangep(new AstRange(varp->fileline(), newvarp->msb(), newvarp->lsb()));
dtypep->rangep()->littleEndian(basicp->littleEndian());
newvarp->varp(new AstVar(varp->fileline(), AstVarType::VAR, name, dtypep));
newvarp->varp()->propagateAttrFrom(varp);
newvarp->varp()->funcLocal(varp->isFuncLocal() || varp->isFuncReturn());
// newvarp->varp()->trace(varp->isTrace()); // Enable this line to trace split
// variable directly
m_netp->typeTablep()->addTypesp(dtypep);
varp->addNextHere(newvarp->varp());
UINFO(4, newvarp->varp()->prettyNameQ()
<< " is added for " << varp->prettyNameQ() << '\n');
}
createVars(varp, it->second.basicp(), vars); // Add the split variables
updateReferences(varp, it->second, vars);
for (int lvalue = 0; lvalue <= 1; ++lvalue) { // Refer the new split variables
std::vector<PackedVarRefEntry>& refs
= lvalue ? it->second.lhs() : it->second.rhs();
for (PackedVarRef::iterator refit = refs.begin(), refitend = refs.end();
refit != refitend; ++refit) {
NewVars::const_iterator varit = std::upper_bound(
vars.begin(), vars.end(), refit->lsb(), SplitNewVar::Match());
UASSERT_OBJ(varit != vars.end(), refit->nodep(), "Not found");
UASSERT(!(varit->msb() < refit->lsb() || refit->msb() < varit->lsb()),
"wrong search result");
AstNode* prev;
bool inSentitivityList = false;
if (AstSenItem* senitemp = refit->backSenItemp()) {
AstNode* oldsenrefp = senitemp->sensp();
oldsenrefp->replaceWith(new AstVarRef(senitemp->fileline(), varit->varp(), false));
VL_DO_DANGLING(oldsenrefp->deleteTree(), oldsenrefp);
prev = senitemp;
inSentitivityList = true;
} else {
prev = extractBits(*refit, *varit, lvalue);
}
for (int residue = refit->msb() - varit->msb(); residue > 0;
residue -= varit->bitwidth()) {
++varit;
UASSERT_OBJ(varit != vars.end(), refit->nodep(),
"not enough split variables");
if (AstSenItem* senitemp = VN_CAST(prev, SenItem)) {
prev = new AstSenItem(senitemp->fileline(), senitemp->edgeType(),
new AstVarRef(senitemp->fileline(), varit->varp(), false));
senitemp->addNextHere(prev);
} else {
AstNode* bitsp = extractBits(*refit, *varit, lvalue);
prev = new AstConcat(refit->nodep()->fileline(), bitsp, prev);
}
}
if (!inSentitivityList) refit->replaceNodeWith(prev);
UASSERT_OBJ(varit->msb() >= refit->msb(), varit->varp(), "Out of range");
}
}
if (varp->isIO()) { // port cannot be deleted
connectPortAndVar(vars, varp);
// If varp is a port of a module, single AssignW is sufficient.
if (!(varp->isFuncLocal() || varp->isFuncReturn()))
connectPortAndVar(vars, varp, NULL);
} else if (varp->isTrace()) {
// Let's reuse the original variable for tracing
AstNode* rhs