Support string putc, getc, substr, bug1606.

Signed-off-by: Wilson Snyder <[email protected]>
This commit is contained in:
Yutetsu TAKATSUKASA
2019-12-15 08:09:52 -05:00
committed by Wilson Snyder
parent 460e0541f3
commit 8cdc0c4e00
11 changed files with 268 additions and 25 deletions
+72
View File
@@ -5995,6 +5995,78 @@ public:
virtual string emitC() { return "hypot(%li,%ri)"; }
};
class AstPutcN : public AstNodeTriop {
// Verilog string.putc()
public:
AstPutcN(FileLine* fl, AstNode* lhsp, AstNode* rhsp, AstNode* ths) : AstNodeTriop(fl, lhsp, rhsp, ths) {
dtypeSetString();
}
ASTNODE_NODE_FUNCS(PutcN)
virtual void numberOperate(V3Number& out, const V3Number& lhs,
const V3Number& rhs, const V3Number& ths) {
out.opPutcN(lhs, rhs, ths);
}
virtual string name() const { return "putc"; }
virtual string emitVerilog() { return "%k(%l.putc(%r,%t))"; }
virtual string emitC() { return "VL_PUTC_N(%li,%ri,%ti)"; }
virtual string emitSimpleOperator() { return ""; }
virtual bool cleanOut() const { return true; }
virtual bool cleanLhs() const { return true; }
virtual bool cleanRhs() const { return true; }
virtual bool cleanThs() const { return true; }
virtual bool sizeMattersLhs() const { return false; }
virtual bool sizeMattersRhs() const { return false; }
virtual bool sizeMattersThs() const { return false; }
};
class AstGetcN : public AstNodeBiop {
// Verilog string.getc()
public:
AstGetcN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) {
dtypeSetBitSized(8, AstNumeric::UNSIGNED);
}
ASTNODE_NODE_FUNCS(GetcN)
virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) {
return new AstGetcN(this->fileline(), lhsp, rhsp);
}
virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) {
out.opGetcN(lhs, rhs);
}
virtual string name() const { return "getc"; }
virtual string emitVerilog() { return "%k(%l.getc(%r))"; }
virtual string emitC() { return "VL_GETC_N(%li,%ri)"; }
virtual string emitSimpleOperator() { return ""; }
virtual bool cleanOut() const { return true; }
virtual bool cleanLhs() const { return true; }
virtual bool cleanRhs() const { return true; }
virtual bool sizeMattersLhs() const { return false; }
virtual bool sizeMattersRhs() const { return false; }
};
class AstSubstrN : public AstNodeTriop {
// Verilog string.substr()
public:
AstSubstrN(FileLine* fl, AstNode* lhsp, AstNode* rhsp, AstNode* ths) : AstNodeTriop(fl, lhsp, rhsp, ths) {
dtypeSetString();
}
ASTNODE_NODE_FUNCS(SubstrN)
virtual void numberOperate(V3Number& out, const V3Number& lhs,
const V3Number& rhs, const V3Number& ths) {
out.opSubstrN(lhs, rhs, ths);
}
virtual string name() const { return "substr"; }
virtual string emitVerilog() { return "%k(%l.substr(%r,%t))"; }
virtual string emitC() { return "VL_SUBSTR_N(%li,%ri,%ti)"; }
virtual string emitSimpleOperator() { return ""; }
virtual bool cleanOut() const { return true; }
virtual bool cleanLhs() const { return true; }
virtual bool cleanRhs() const { return true; }
virtual bool cleanThs() const { return true; }
virtual bool sizeMattersLhs() const { return false; }
virtual bool sizeMattersRhs() const { return false; }
virtual bool sizeMattersThs() const { return false; }
};
class AstCompareNN : public AstNodeBiop {
// Verilog str.compare() and str.icompare()
private:
+2
View File
@@ -2526,6 +2526,8 @@ private:
TREEOPV("AstLogIf{$lhsp, $rhsp}", "AstLogOr{AstLogNot{$lhsp},$rhsp}");
TREEOPV("AstLogEq{$lhsp, $rhsp}", "replaceLogEq(nodep)");
// Strings
TREEOPC("AstPutcN{$lhsp.castConst, $rhsp.castConst, $thsp.castConst}", "replaceConst(nodep)");
TREEOPC("AstSubstrN{$lhsp.castConst, $rhsp.castConst, $thsp.castConst}", "replaceConst(nodep)");
TREEOPC("AstCvtPackString{$lhsp.castConst}", "replaceConstString(nodep, VN_CAST(nodep->lhsp(), Const)->num().toString())");
+4
View File
@@ -643,6 +643,10 @@ public:
emitOpName(nodep, nodep->emitC(), nodep->lhsp(), nodep->rhsp(), NULL);
}
}
virtual void visit(AstNodeTriop* nodep) {
UASSERT_OBJ(!emitSimpleOk(nodep), nodep, "Triop cannot be described in a simple way");
emitOpName(nodep, nodep->emitC(), nodep->lhsp(), nodep->rhsp(), nodep->thsp());
}
virtual void visit(AstRedXor* nodep) {
if (nodep->lhsp()->isWide()) {
visit(VN_CAST(nodep, NodeUniop));
+12
View File
@@ -62,6 +62,18 @@ class EmitCInlines : EmitCBaseVisitor {
v3Global.needHeavy(true);
iterateChildren(nodep);
}
virtual void visit(AstPutcN* nodep) {
v3Global.needHeavy(true);
iterateChildren(nodep);
}
virtual void visit(AstGetcN* nodep) {
v3Global.needHeavy(true);
iterateChildren(nodep);
}
virtual void visit(AstSubstrN* nodep) {
v3Global.needHeavy(true);
iterateChildren(nodep);
}
virtual void visit(AstCompareNN* nodep) {
v3Global.needHeavy(true);
iterateChildren(nodep);
+38
View File
@@ -1262,6 +1262,44 @@ V3Number& V3Number::opAtoN(const V3Number& lhs, int base) {
return setLongS(static_cast<vlsint32_t>(v));
}
V3Number& V3Number::opPutcN(const V3Number& lhs, const V3Number& rhs, const V3Number& ths) {
NUM_ASSERT_OP_ARGS3(lhs, rhs, ths);
NUM_ASSERT_STRING_ARGS1(lhs);
string lstring = lhs.toString();
const vlsint32_t i = rhs.toSInt();
const vlsint32_t c = ths.toSInt() & 0xFF;
// 6.16.2:str.putc(i, c) does not change the value when i < 0 || i >= str.len() || c == 0
// when evaluating the second condition, i must be positive.
if (0 <= i && static_cast<uint32_t>(i) < lstring.length() && c != 0) lstring[i] = c;
return setString(lstring);
}
V3Number& V3Number::opGetcN(const V3Number& lhs, const V3Number& rhs) {
NUM_ASSERT_OP_ARGS2(lhs, rhs);
NUM_ASSERT_STRING_ARGS1(lhs);
const string lstring = lhs.toString();
const vlsint32_t i = rhs.toSInt();
vlsint32_t v = 0;
// 6.16.3:str.getc(i) returns 0 if i < 0 || i >= str.len()
// when evaluating the second condition, i must be positive.
if (0 <= i && static_cast<uint32_t>(i) < lstring.length()) v = lstring[i];
return setLong(v);
}
V3Number& V3Number::opSubstrN(const V3Number& lhs, const V3Number& rhs, const V3Number& ths) {
NUM_ASSERT_OP_ARGS3(lhs, rhs, ths);
NUM_ASSERT_STRING_ARGS1(lhs);
const string lstring = lhs.toString();
const vlsint32_t i = rhs.toSInt();
const vlsint32_t j = ths.toSInt();
// 6.16.8:str.substr(i, j) returns an empty string when i < 0 || j < i || j >= str.len()
// when evaluating the third condition, j must be positive because 0 <= i <= j is guaranteed by
// the former two conditions.
if (i < 0 || j < i || static_cast<uint32_t>(j) >= lstring.length()) return setString("");
// The second parameter of std::string::substr(i, n) is length, not position as SystemVerilog.
return setString(lstring.substr(i, j - i + 1));
}
V3Number& V3Number::opCompareNN(const V3Number& lhs, const V3Number& rhs, bool ignoreCase) {
NUM_ASSERT_OP_ARGS2(lhs, rhs);
NUM_ASSERT_STRING_ARGS2(lhs, rhs);
+3
View File
@@ -361,6 +361,9 @@ public:
// "N" - string operations
V3Number& opAtoN (const V3Number& lhs, int base);
V3Number& opPutcN (const V3Number& lhs, const V3Number& rhs, const V3Number& ths);
V3Number& opGetcN (const V3Number& lhs, const V3Number& rhs);
V3Number& opSubstrN (const V3Number& lhs, const V3Number& rhs, const V3Number& ths);
V3Number& opCompareNN(const V3Number& lhs,const V3Number& rhs, bool ignoreCase);
V3Number& opConcatN (const V3Number& lhs, const V3Number& rhs);
V3Number& opReplN (const V3Number& lhs, const V3Number& rhs);
+60 -3
View File
@@ -333,6 +333,38 @@ private:
// Output integer, input string
virtual void visit(AstLenN* nodep) { visit_Os32_string(nodep); }
virtual void visit(AstPutcN* nodep) {
// CALLER: str.putc()
UASSERT_OBJ(nodep->rhsp() && nodep->thsp(), nodep, "For ternary ops only!");
if (m_vup && m_vup->prelim()) {
// See similar handling in visit_cmp_eq_gt where created
iterateCheckString(nodep, "LHS", nodep->lhsp(), BOTH);
iterateCheckSigned32(nodep, "RHS", nodep->rhsp(), BOTH);
iterateCheckSigned32(nodep, "THS", nodep->thsp(), BOTH);
nodep->dtypeSetString(); //AstPutcN returns the new string to be assigned by AstAssign
}
}
virtual void visit(AstGetcN* nodep) {
// CALLER: str.getc()
UASSERT_OBJ(nodep->rhsp(), nodep, "For binary ops only!");
if (m_vup && m_vup->prelim()) {
// See similar handling in visit_cmp_eq_gt where created
iterateCheckString(nodep, "LHS", nodep->lhsp(), BOTH);
iterateCheckSigned32(nodep, "RHS", nodep->rhsp(), BOTH);
nodep->dtypeSetBitSized(8, AstNumeric::UNSIGNED);
}
}
virtual void visit(AstSubstrN* nodep) {
// CALLER: str.substr()
UASSERT_OBJ(nodep->rhsp() && nodep->thsp(), nodep, "For ternary ops only!");
if (m_vup && m_vup->prelim()) {
// See similar handling in visit_cmp_eq_gt where created
iterateCheckString(nodep, "LHS", nodep->lhsp(), BOTH);
iterateCheckSigned32(nodep, "RHS", nodep->rhsp(), BOTH);
iterateCheckSigned32(nodep, "THS", nodep->thsp(), BOTH);
nodep->dtypeSetString();
}
}
virtual void visit(AstCompareNN* nodep) {
// CALLER: str.compare(), str.icompare()
// Widths: 32 bit out
@@ -2115,6 +2147,34 @@ private:
AstNode* rhs = argp->exprp()->unlinkFrBack();
AstNode* newp = new AstCompareNN(nodep->fileline(), lhs, rhs, ignoreCase);
nodep->replaceWith(newp); nodep->deleteTree(); VL_DANGLING(nodep);
} else if (nodep->name() == "putc" ) {
methodOkArguments(nodep, 2, 2);
AstArg* arg0p = VN_CAST(nodep->pinsp(), Arg);
AstArg* arg1p = VN_CAST(arg0p->nextp(), Arg);
AstNodeVarRef* fromp = VN_CAST(nodep->fromp()->unlinkFrBack(), VarRef);
AstNode* rhsp = arg0p->exprp()->unlinkFrBack();
AstNode* thsp = arg1p->exprp()->unlinkFrBack();
AstVarRef* varrefp = new AstVarRef(nodep->fileline(), fromp->varp(), false);
AstNode* newp = new AstAssign(nodep->fileline(), fromp,
new AstPutcN(nodep->fileline(), varrefp, rhsp, thsp));
fromp->lvalue(true);
nodep->replaceWith(newp); nodep->deleteTree(); VL_DANGLING(nodep);
} else if (nodep->name() == "getc") {
methodOkArguments(nodep, 1, 1);
AstArg* arg0p = VN_CAST(nodep->pinsp(), Arg);
AstNode* lhsp = nodep->fromp()->unlinkFrBack();
AstNode* rhsp = arg0p->exprp()->unlinkFrBack();
AstNode* newp = new AstGetcN(nodep->fileline(), lhsp, rhsp);
nodep->replaceWith(newp); nodep->deleteTree(); VL_DANGLING(nodep);
} else if (nodep->name() == "substr") {
methodOkArguments(nodep, 2, 2);
AstArg* arg0p = VN_CAST(nodep->pinsp(), Arg);
AstArg* arg1p = VN_CAST(arg0p->nextp(), Arg);
AstNode* lhsp = nodep->fromp()->unlinkFrBack();
AstNode* rhsp = arg0p->exprp()->unlinkFrBack();
AstNode* thsp = arg1p->exprp()->unlinkFrBack();
AstNode* newp = new AstSubstrN(nodep->fileline(), lhsp, rhsp, thsp);
nodep->replaceWith(newp); nodep->deleteTree(); VL_DANGLING(nodep);
} else if (nodep->name() == "atobin"
|| nodep->name() == "atohex"
|| nodep->name() == "atoi"
@@ -2130,9 +2190,6 @@ private:
methodOkArguments(nodep, 0, 0);
AstNode* newp = new AstAtoN(nodep->fileline(), nodep->fromp()->unlinkFrBack(), fmt);
nodep->replaceWith(newp); nodep->deleteTree(); VL_DANGLING(nodep);
} else if (nodep->name() == "getc"
|| nodep->name() == "putc") {
nodep->v3error("Unsupported: built-in string method "<<nodep->prettyNameQ());
} else {
nodep->v3error("Unknown built-in string method "<<nodep->prettyNameQ());
}