Esempio n. 1
0
bool
Instruction::writesPredicate() const
{
   for (int d = 0; defExists(d); ++d)
      if (getDef(d)->inFile(FILE_PREDICATE) || getDef(d)->inFile(FILE_FLAGS))
         return true;
   return false;
}
Esempio n. 2
0
bool
Instruction::canCommuteDefDef(const Instruction *i) const
{
   for (int d = 0; defExists(d); ++d)
      for (int c = 0; i->defExists(c); ++c)
         if (getDef(d)->interfers(i->getDef(c)))
            return false;
   return true;
}
Esempio n. 3
0
bool
Instruction::canCommuteDefSrc(const Instruction *i) const
{
   for (int d = 0; defExists(d); ++d)
      for (int s = 0; i->srcExists(s); ++s)
         if (getDef(d)->interfers(i->getSrc(s)))
            return false;
   return true;
}
void V3PreProcImp::define(FileLine* fl, const string& name, const string& value,
			  const string& params, bool cmdline) {
    UINFO(4,"DEFINE '"<<name<<"' as '"<<value<<"' params '"<<params<<"'"<<endl);
    if (defExists(name)) {
	if (!(defValue(name)==value && defParams(name)==params)) {  // Duplicate defs are OK
	    fl->v3warn(REDEFMACRO,"Redefining existing define: "<<name<<", with different value: "<<value<<" "<<params);
	    defFileline(name)->v3warn(REDEFMACRO,"Previous definition is here, with value: "<<defValue(name)<<" "<<defParams(name));
	}
	undef(name);
    }
    m_defines.insert(make_pair(name, V3Define(fl, value, params, cmdline)));
}
Esempio n. 5
0
Instruction::~Instruction()
{
   if (bb) {
      Function *fn = bb->getFunction();
      bb->remove(this);
      fn->allInsns.remove(id);
   }

   for (int s = 0; srcExists(s); ++s)
      setSrc(s, NULL);
   // must unlink defs too since the list pointers will get deallocated
   for (int d = 0; defExists(d); ++d)
      setDef(d, NULL);
}
string V3PreProcImp::removeDefines(const string& sym) {
    string val = "0_never_match";
    string rtnsym = sym;
    for (int loopprevent=0; loopprevent<100; loopprevent++) {
	string xsym = rtnsym;
	if (xsym.substr(0,1)=="`") xsym.replace(0,1,"");
        if (defExists(xsym)) {
	    val = defValue(xsym);
	    if (val != rtnsym) rtnsym=val;  // Prevent infinite loop if have `define X X
	    else break;
        } else break;
    }
    return rtnsym;  // NA
}
Esempio n. 7
0
unsigned int
Instruction::defCount(unsigned int mask, bool singleFile) const
{
   unsigned int i, n;

   if (singleFile) {
      unsigned int d = ffs(mask);
      if (!d)
         return 0;
      for (i = d--; defExists(i); ++i)
         if (getDef(i)->reg.file != getDef(d)->reg.file)
            mask &= ~(1 << i);
   }

   for (n = 0, i = 0; this->defExists(i); ++i, mask >>= 1)
      n += mask & 1;
   return n;
}
Esempio n. 8
0
Instruction *
Instruction::clone(ClonePolicy<Function>& pol, Instruction *i) const
{
   if (!i)
      i = new_Instruction(pol.context(), op, dType);
#ifndef NDEBUG // non-conformant assert, so this is required
   assert(typeid(*i) == typeid(*this));
#endif

   pol.set<Instruction>(this, i);

   i->sType = sType;

   i->rnd = rnd;
   i->cache = cache;
   i->subOp = subOp;

   i->saturate = saturate;
   i->join = join;
   i->exit = exit;
   i->mask = mask;
   i->ftz = ftz;
   i->dnz = dnz;
   i->ipa = ipa;
   i->lanes = lanes;
   i->perPatch = perPatch;

   i->postFactor = postFactor;

   for (int d = 0; defExists(d); ++d)
      i->setDef(d, pol.get(getDef(d)));

   for (int s = 0; srcExists(s); ++s) {
      i->setSrc(s, pol.get(getSrc(s)));
      i->src(s).mod = src(s).mod;
   }

   i->cc = cc;
   i->predSrc = predSrc;
   i->flagsDef = flagsDef;
   i->flagsSrc = flagsSrc;

   return i;
}
Esempio n. 9
0
void Instruction::print() const
{
   #define BUFSZ 512

   const size_t size = BUFSZ;

   char buf[BUFSZ];
   int s, d;
   size_t pos = 0;

   PRINT("%s", colour[TXT_INSN]);

   if (join)
      PRINT("join ");

   if (predSrc >= 0) {
      const size_t pre = pos;
      if (getSrc(predSrc)->reg.file == FILE_PREDICATE) {
         if (cc == CC_NOT_P)
            PRINT("not");
      } else {
         PRINT("%s", CondCodeStr[cc]);
      }
      if (pos > pre)
         SPACE();
      pos += getSrc(predSrc)->print(&buf[pos], BUFSZ - pos);
      PRINT(" %s", colour[TXT_INSN]);
   }

   if (saturate)
      PRINT("sat ");

   if (asFlow()) {
      PRINT("%s", operationStr[op]);
      if (asFlow()->indirect)
         PRINT(" ind");
      if (asFlow()->absolute)
         PRINT(" abs");
      if (op == OP_CALL && asFlow()->builtin) {
         PRINT(" %sBUILTIN:%i", colour[TXT_BRA], asFlow()->target.builtin);
      } else
      if (op == OP_CALL && asFlow()->target.fn) {
         PRINT(" %s%s:%i", colour[TXT_BRA],
               asFlow()->target.fn->getName(),
               asFlow()->target.fn->getLabel());
      } else
      if (asFlow()->target.bb)
         PRINT(" %sBB:%i", colour[TXT_BRA], asFlow()->target.bb->getId());
   } else {
      PRINT("%s ", operationStr[op]);
      if (op == OP_LINTERP || op == OP_PINTERP)
         PRINT("%s ", interpStr[ipa]);
      switch (op) {
      case OP_SUREDP:
      case OP_ATOM:
         if (subOp < ARRAY_SIZE(atomSubOpStr))
            PRINT("%s ", atomSubOpStr[subOp]);
         break;
      case OP_LOAD:
      case OP_STORE:
         if (subOp < ARRAY_SIZE(ldstSubOpStr))
            PRINT("%s ", ldstSubOpStr[subOp]);
         break;
      case OP_SUBFM:
         if (subOp < ARRAY_SIZE(subfmOpStr))
            PRINT("%s ", subfmOpStr[subOp]);
         break;
      case OP_SHFL:
         if (subOp < ARRAY_SIZE(shflOpStr))
            PRINT("%s ", shflOpStr[subOp]);
         break;
      case OP_PIXLD:
         if (subOp < ARRAY_SIZE(pixldOpStr))
            PRINT("%s ", pixldOpStr[subOp]);
         break;
      case OP_RCP:
      case OP_RSQ:
         if (subOp < ARRAY_SIZE(rcprsqOpStr))
            PRINT("%s ", rcprsqOpStr[subOp]);
         break;
      case OP_EMIT:
         if (subOp < ARRAY_SIZE(emitOpStr))
            PRINT("%s ", emitOpStr[subOp]);
         break;
      default:
         if (subOp)
            PRINT("(SUBOP:%u) ", subOp);
         break;
      }
      if (perPatch)
         PRINT("patch ");
      if (asTex())
         PRINT("%s %s$r%u $s%u %s", asTex()->tex.target.getName(),
               colour[TXT_MEM], asTex()->tex.r, asTex()->tex.s,
               colour[TXT_INSN]);
      if (postFactor)
         PRINT("x2^%i ", postFactor);
      PRINT("%s%s", dnz ? "dnz " : (ftz ? "ftz " : ""),  DataTypeStr[dType]);
   }

   if (rnd != ROUND_N)
      PRINT(" %s", RoundModeStr[rnd]);

   if (defExists(1))
      PRINT(" {");
   for (d = 0; defExists(d); ++d) {
      SPACE();
      pos += getDef(d)->print(&buf[pos], size - pos);
   }
   if (d > 1)
      PRINT(" %s}", colour[TXT_INSN]);
   else
   if (!d && !asFlow())
      PRINT(" %s#", colour[TXT_INSN]);

   if (asCmp())
      PRINT(" %s%s", colour[TXT_INSN], CondCodeStr[asCmp()->setCond]);

   if (sType != dType)
      PRINT(" %s%s", colour[TXT_INSN], DataTypeStr[sType]);

   for (s = 0; srcExists(s); ++s) {
      if (s == predSrc || src(s).usedAsPtr)
         continue;
      const size_t pre = pos;
      SPACE();
      pos += src(s).mod.print(&buf[pos], BUFSZ - pos);
      if (pos > pre + 1)
         SPACE();
      if (src(s).isIndirect(0) || src(s).isIndirect(1))
         pos += getSrc(s)->asSym()->print(&buf[pos], BUFSZ - pos,
                                          getIndirect(s, 0),
                                          getIndirect(s, 1));
      else
         pos += getSrc(s)->print(&buf[pos], BUFSZ - pos, sType);
   }
   if (exit)
      PRINT("%s exit", colour[TXT_INSN]);

   PRINT("%s", colour[TXT_DEFAULT]);

   buf[MIN2(pos, BUFSZ - 1)] = 0;

   INFO("%s (%u)\n", buf, encSize);
}
int V3PreProcImp::getStateToken() {
    // Return the next state-determined token
    while (1) {
      next_tok:
	if (isEof()) return VP_EOF;
	int tok = getRawToken();
	ProcState state = m_states.top();

	// Most states emit white space and comments between tokens. (Unless collecting a string)
	if (tok==VP_WHITE && state !=ps_STRIFY) return (tok);
	if (tok==VP_BACKQUOTE && state !=ps_STRIFY) { tok = VP_TEXT; }
	if (tok==VP_COMMENT) {
	    if (!m_off) {
		if (m_lexp->m_keepComments == KEEPCMT_SUB) {
		    string rtn; rtn.assign(yyourtext(),yyourleng());
		    comment(rtn);
		    // Need to insure "foo/**/bar" becomes two tokens
		    insertUnreadback (" ");
		} else if (m_lexp->m_keepComments) {
		    return (tok);
		} else {
		    // Need to insure "foo/**/bar" becomes two tokens
		    insertUnreadback (" ");
		}
	    }
	    // We're off or processed the comment specially.  If there are newlines
	    // in it, we also return the newlines as TEXT so that the linenumber
	    // count is maintained for downstream tools
	    for (size_t len=0; len<(size_t)yyourleng(); len++) { if (yyourtext()[len]=='\n') m_lineAdd++; }
	    goto next_tok;
	}
	if (tok==VP_LINE) {
	    addLineComment(m_lexp->m_enterExit);
	    goto next_tok;
	}

	if (tok==VP_DEFREF_JOIN) {
	    // Here's something fun and unspecified as yet:
	    // The existance of non-existance of a base define changes `` expansion
	    //	`define QA_b zzz
	    //	`define Q1 `QA``_b
	    //	 1Q1 -> zzz
	    //	`define QA a
	    //	 `Q1 -> a_b
	    // Note parenthesis make this unambiguous
	    //	`define Q1 `QA()``_b  // -> a_b
	    // This may be a side effect of how `UNDEFINED remains as `UNDEFINED,
	    // but it screws up our method here.  So hardcode it.
	    string name (yyourtext()+1,yyourleng()-1);
	    if (defExists(name)) {   // JOIN(DEFREF)
		// Put back the `` and process the defref
		UINFO(5,"```: define "<<name<<" exists, expand first\n");
		m_defPutJoin = true;  // After define, unputString("``").  Not now as would lose yyourtext()
		UINFO(5,"TOKEN now DEFREF\n");
		tok = VP_DEFREF;
	    } else {  // DEFREF(JOIN)
		UINFO(5,"```: define "<<name<<" doesn't exist, join first\n");
		// FALLTHRU, handle as with VP_SYMBOL_JOIN
	    }
	}
	if (tok==VP_SYMBOL_JOIN || tok==VP_DEFREF_JOIN) {  // not else if, can fallthru from above if()
	    // a`` -> string doesn't include the ``, so can just grab next and continue
	    string out (yyourtext(),yyourleng());
	    UINFO(5,"`` LHS:"<<out<<endl);
	    // a``b``c can have multiple joins, so we need a stack
	    m_joinStack.push(out);
	    statePush(ps_JOIN);
	    goto next_tok;
	}

	// Deal with some special parser states
	switch (state) {
	case ps_TOP: {
	    break;
	}
	case ps_DEFNAME_UNDEF:	// FALLTHRU
	case ps_DEFNAME_DEFINE:	// FALLTHRU
	case ps_DEFNAME_IFDEF:	// FALLTHRU
	case ps_DEFNAME_IFNDEF:	// FALLTHRU
	case ps_DEFNAME_ELSIF: {
	    if (tok==VP_SYMBOL) {
		m_lastSym.assign(yyourtext(),yyourleng());
		if (state==ps_DEFNAME_IFDEF
		    || state==ps_DEFNAME_IFNDEF) {
		    bool enable = defExists(m_lastSym);
		    UINFO(4,"Ifdef "<<m_lastSym<<(enable?" ON":" OFF")<<endl);
		    if (state==ps_DEFNAME_IFNDEF) enable = !enable;
		    m_ifdefStack.push(VPreIfEntry(enable,false));
		    if (!enable) parsingOff();
		    statePop();
		    goto next_tok;
		}
		else if (state==ps_DEFNAME_ELSIF) {
		    if (m_ifdefStack.empty()) {
			error("`elsif with no matching `if\n");
		    } else {
			// Handle `else portion
			VPreIfEntry lastIf = m_ifdefStack.top(); m_ifdefStack.pop();
			if (!lastIf.on()) parsingOn();
			// Handle `if portion
			bool enable = !lastIf.everOn() && defExists(m_lastSym);
			UINFO(4,"Elsif "<<m_lastSym<<(enable?" ON":" OFF")<<endl);
			m_ifdefStack.push(VPreIfEntry(enable, lastIf.everOn()));
			if (!enable) parsingOff();
		    }
		    statePop();
		    goto next_tok;
		}
		else if (state==ps_DEFNAME_UNDEF) {
		    if (!m_off) {
			UINFO(4,"Undef "<<m_lastSym<<endl);
			undef(m_lastSym);
		    }
		    statePop();
		    goto next_tok;
		}
		else if (state==ps_DEFNAME_DEFINE) {
		    // m_lastSym already set.
		    stateChange(ps_DEFFORM);
		    m_lexp->pushStateDefForm();
		    goto next_tok;
		}
		else fatalSrc("Bad case\n");
		goto next_tok;
	    }
	    else if (tok==VP_TEXT) {
		// IE, something like comment between define and symbol
		if (!m_off) return tok;
		else goto next_tok;
	    }
	    else if (tok==VP_DEFREF) {
		// IE, `ifdef `MACRO(x): Substitue and come back here when state pops.
		break;
	    }
	    else {
		error((string)"Expecting define name. Found: "+tokenName(tok)+"\n");
		goto next_tok;
	    }
	}
	case ps_DEFFORM: {
	    if (tok==VP_DEFFORM) {
		m_formals = m_lexp->m_defValue;
		if (debug()>=5) cout<<"DefFormals='"<<V3PreLex::cleanDbgStrg(m_formals)<<"'\n";
		stateChange(ps_DEFVALUE);
		m_lexp->pushStateDefValue();
		goto next_tok;
	    } else if (tok==VP_TEXT) {
		// IE, something like comment in formals
		if (!m_off) return tok;
		else goto next_tok;
	    } else {
		error((string)"Expecting define formal arguments. Found: "+tokenName(tok)+"\n");
		goto next_tok;
	    }
	}
	case ps_DEFVALUE: {
	    static string newlines;
	    newlines = "\n";  // Always start with trailing return
	    if (tok == VP_DEFVALUE) {
		if (debug()>=5) cout<<"DefValue='"<<V3PreLex::cleanDbgStrg(m_lexp->m_defValue)
				    <<"'  formals='"<<V3PreLex::cleanDbgStrg(m_formals)<<"'\n";
		// Add any formals
		string formals = m_formals;
		string value = m_lexp->m_defValue;
		// Remove returns
		// Not removing returns in values has two problems,
		// 1. we need to correct line numbers with `line after each substitution
		// 2. Substituting in " .... " with embedded returns requires \ escape.
		//    This is very difficult in the presence of `", so we keep the \ before the newline.
		for (size_t i=0; i<formals.length(); i++) {
		    if (formals[i] == '\n') {
			newlines += "\n";
		    }
		}
		for (size_t i=0; i<value.length(); i++) {
		    if (value[i] == '\n') {
			newlines += "\n";
		    }
		}
		if (!m_off) {
		    // Remove leading and trailing whitespace
		    value = trimWhitespace(value, true);
		    // Define it
		    UINFO(4,"Define "<<m_lastSym<<" "<<formals
			  <<" = '"<<V3PreLex::cleanDbgStrg(value)<<"'"<<endl);
		    define(fileline(), m_lastSym, value, formals, false);
		}
	    } else {
		string msg = string("Bad define text, unexpected ")+tokenName(tok)+"\n";
		fatalSrc(msg);
	    }
	    statePop();
	    // DEFVALUE is terminated by a return, but lex can't return both tokens.
	    // Thus, we emit a return here.
	    yyourtext(newlines.c_str(), newlines.length());
	    return(VP_WHITE);
	}
	case ps_DEFPAREN: {
	    if (tok==VP_TEXT && yyourleng()==1 && yyourtext()[0]=='(') {
		stateChange(ps_DEFARG);
		goto next_tok;
	    } else {
		if (m_defRefs.empty()) fatalSrc("Shouldn't be in DEFPAREN w/o active defref");
		V3DefineRef* refp = &(m_defRefs.top());
		error((string)"Expecting ( to begin argument list for define reference `"+refp->name()+"\n");
		statePop();
		goto next_tok;
	    }
	}
	case ps_DEFARG: {
	    if (m_defRefs.empty()) fatalSrc("Shouldn't be in DEFARG w/o active defref");
	    V3DefineRef* refp = &(m_defRefs.top());
	    refp->nextarg(refp->nextarg()+m_lexp->m_defValue); m_lexp->m_defValue="";
	    UINFO(4,"defarg++ "<<refp->nextarg()<<endl);
	    if (tok==VP_DEFARG && yyourleng()==1 && yyourtext()[0]==',') {
		refp->args().push_back(refp->nextarg());
		stateChange(ps_DEFARG);
		m_lexp->pushStateDefArg(1);
		refp->nextarg("");
		goto next_tok;
	    } else if (tok==VP_DEFARG && yyourleng()==1 && yyourtext()[0]==')') {
		// Substitute in and prepare for next action
		// Similar code in non-parenthesized define (Search for END_OF_DEFARG)
		refp->args().push_back(refp->nextarg());
		string out;
		if (!m_off) {
		    out = defineSubst(refp);
		    //NOP: out = m_preprocp->defSubstitute(out);
		}
		m_defRefs.pop();  refp=NULL;
		if (m_defRefs.empty()) {
		    statePop();
		    if (!m_off) unputDefrefString(out);
		    m_lexp->m_parenLevel = 0;
		}
		else {  // Finished a defref inside a upper defref
		    // Can't subst now, or
		    // `define a(ign) x,y
		    // foo(`a(ign),`b)  would break because a contains comma
		    refp = &(m_defRefs.top());  // We popped, so new top
		    refp->nextarg(refp->nextarg()+m_lexp->m_defValue+out); m_lexp->m_defValue="";
		    m_lexp->m_parenLevel = refp->parenLevel();
		    statePop();  // Will go to ps_DEFARG, as we're under another define
		}
		goto next_tok;
	    } else if (tok==VP_DEFREF) {
		// Expand it, then state will come back here
		// Value of building argument is data before the lower defref
		// we'll append it when we push the argument.
		break;
	    } else if (tok==VP_SYMBOL || tok==VP_STRING || VP_TEXT || VP_WHITE) {
		string rtn; rtn.assign(yyourtext(),yyourleng());
		refp->nextarg(refp->nextarg()+rtn);
		goto next_tok;
	    } else {
		error((string)"Expecting ) or , to end argument list for define reference. Found: "+tokenName(tok));
		statePop();
		goto next_tok;
	    }
	}
	case ps_INCNAME: {
	    if (tok==VP_STRING) {
		statePop();
		m_lastSym.assign(yyourtext(),yyourleng());
		UINFO(4,"Include "<<m_lastSym<<endl);
		// Drop leading and trailing quotes.
		m_lastSym.erase(0,1);
		m_lastSym.erase(m_lastSym.length()-1,1);
		include(m_lastSym);
		goto next_tok;
	    }
	    else if (tok==VP_TEXT && yyourleng()==1 && yyourtext()[0]=='<') {
		// include <filename>
		stateChange(ps_INCNAME);  // Still
		m_lexp->pushStateIncFilename();
		goto next_tok;
	    }
	    else if (tok==VP_DEFREF
		     || tok==VP_STRIFY) {
		// Expand it, then state will come back here
		break;
	    }
	    else {
		statePop();
		error((string)"Expecting include filename. Found: "+tokenName(tok)+"\n");
		goto next_tok;
	    }
	}
	case ps_ERRORNAME: {
	    if (tok==VP_STRING) {
		if (!m_off) {
		    m_lastSym.assign(yyourtext(),yyourleng());
		    error(m_lastSym);
		}
		statePop();
		goto next_tok;
	    }
	    else {
		error((string)"Expecting `error string. Found: "+tokenName(tok)+"\n");
		statePop();
		goto next_tok;
	    }
	}
	case ps_JOIN: {
	    if (tok==VP_SYMBOL || tok==VP_TEXT) {
		if (m_joinStack.empty()) fatalSrc("`` join stack empty, but in a ``");
		string lhs = m_joinStack.top(); m_joinStack.pop();
		UINFO(5,"`` LHS:"<<lhs<<endl);
		string rhs (yyourtext(),yyourleng());
		UINFO(5,"`` RHS:"<<rhs<<endl);
		string out = lhs+rhs;
		UINFO(5,"`` Out:"<<out<<endl);
		unputString(out);
		statePop();
		goto next_tok;
	    } else if (tok==VP_EOF || tok==VP_WHITE || tok == VP_COMMENT || tok==VP_STRING) {
		error((string)"Expecting symbol to terminate ``; whitespace etc cannot follow ``. Found: "+tokenName(tok)+"\n");
		statePop();
		goto next_tok;
	    } else {
		// `define, etc, fall through and expand.  Pop back here.
		break;
	    }
	}
	case ps_STRIFY: {
	    if (tok==VP_STRIFY) {
		// Quote what's in the middle of the stringification
		// Note a `" MACRO_WITH(`") `" doesn't need to be handled (we don't need a stack)
		// That behavior isn't specified, and other simulators vary widely
		string out = m_strify;
		m_strify = "";
		// Convert any newlines to spaces, so we don't get a multiline "..." without \ escapes
		// The spec is silent about this either way; simulators vary
		string::size_type pos;
		while ((pos=out.find("\n")) != string::npos) {
		    out.replace(pos, 1, " ");
		}
		unputString((string)"\""+out+"\"");
		statePop();
		goto next_tok;
	    }
	    else if (tok==VP_EOF) {
		error("`\" not terminated at EOF\n");
	    }
	    else if (tok==VP_BACKQUOTE) {
		m_strify += "\\\"";
		goto next_tok;
	    }
	    else if (tok==VP_DEFREF) {
		// Spec says to expand macros inside `"
		// Substitue it into the stream, then return here
		break;
	    }
	    else {
		// Append token to eventual string
		m_strify.append(yyourtext(),yyourleng());
		goto next_tok;
	    }
	}
	default: fatalSrc("Bad case\n");
	}
	// Default is to do top level expansion of some tokens
	switch (tok) {
	case VP_INCLUDE:
	    if (!m_off) {
		statePush(ps_INCNAME);
	    }
	    goto next_tok;
	case VP_UNDEF:
	    statePush(ps_DEFNAME_UNDEF);
	    goto next_tok;
	case VP_DEFINE:
	    // No m_off check here, as a `ifdef NEVER `define FOO(`endif)  should work
	    statePush(ps_DEFNAME_DEFINE);
	    goto next_tok;
	case VP_IFDEF:
	    statePush(ps_DEFNAME_IFDEF);
	    goto next_tok;
	case VP_IFNDEF:
	    statePush(ps_DEFNAME_IFNDEF);
	    goto next_tok;
	case VP_ELSIF:
	    statePush(ps_DEFNAME_ELSIF);
	    goto next_tok;
	case VP_ELSE:
	    if (m_ifdefStack.empty()) {
		error("`else with no matching `if\n");
	    } else {
		VPreIfEntry lastIf = m_ifdefStack.top(); m_ifdefStack.pop();
		bool enable = !lastIf.everOn();
		UINFO(4,"Else "<<(enable?" ON":" OFF")<<endl);
		m_ifdefStack.push(VPreIfEntry(enable, lastIf.everOn()));
		if (!lastIf.on()) parsingOn();
		if (!enable) parsingOff();
	    }
	    goto next_tok;
	case VP_ENDIF:
	    UINFO(4,"Endif "<<endl);
	    if (m_ifdefStack.empty()) {
		error("`endif with no matching `if\n");
	    } else {
		VPreIfEntry lastIf = m_ifdefStack.top(); m_ifdefStack.pop();
		if (!lastIf.on()) parsingOn();
		// parsingOn() really only enables parsing if
		// all ifdef's above this want it on
	    }
	    goto next_tok;

	case VP_DEFREF: {
	    // m_off not right here, but inside substitution, to make this work: `ifdef NEVER `DEFUN(`endif)
	    string name (yyourtext()+1,yyourleng()-1);
	    UINFO(4,"DefRef "<<name<<endl);
	    if (m_defPutJoin) { m_defPutJoin = false; unputString("``"); }
	    if (m_defDepth++ > V3PreProc::DEFINE_RECURSION_LEVEL_MAX) {
		error("Recursive `define substitution: `"+name);
		goto next_tok;
	    }
	    // substitute
	    if (!defExists(name)) {   // Not found, return original string as-is
		m_defDepth = 0;
		UINFO(4,"Defref `"<<name<<" => not_defined"<<endl);
		if (m_off) {
		    goto next_tok;
		} else {
		    return (VP_TEXT);
		}
	    }
	    else {
		string params = defParams(name);
		if (params=="0" || params=="") {  // Found, as simple substitution
		    if (m_off) {
			goto next_tok;
		    }
		    else {
			V3DefineRef tempref(name, "");
			string out = defineSubst(&tempref);
			// Similar code in parenthesized define (Search for END_OF_DEFARG)
			//NOP: out = m_preprocp->defSubstitute(out);
			if (m_defRefs.empty()) {
			    // Just output the substitution
			    unputDefrefString(out);
			} else {
			    // Inside another define.
			    // Can't subst now, or
			    // `define a x,y
			    // foo(`a,`b)  would break because a contains comma
			    V3DefineRef* refp = &(m_defRefs.top());
			    refp->nextarg(refp->nextarg()+m_lexp->m_defValue+out); m_lexp->m_defValue="";
			}
			goto next_tok;
		    }
		}
		else {  // Found, with parameters
		    UINFO(4,"Defref `"<<name<<" => parameterized"<<endl);
		    // The CURRENT macro needs the paren saved, it's not a property of the child macro
		    if (!m_defRefs.empty()) m_defRefs.top().parenLevel(m_lexp->m_parenLevel);
		    m_defRefs.push(V3DefineRef(name, params));
		    statePush(ps_DEFPAREN);
		    m_lexp->pushStateDefArg(0);
		    goto next_tok;
		}
	    }
	    fatalSrc("Bad case\n");
	}
	case VP_ERROR: {
	    statePush(ps_ERRORNAME);
	    goto next_tok;
	}
	case VP_EOF:
	    if (!m_ifdefStack.empty()) {
		error("`ifdef not terminated at EOF\n");
	    }
	    return tok;
	case VP_UNDEFINEALL:
	    if (!m_off) {
		UINFO(4,"Undefineall "<<endl);
		undefineall();
	    }
	    goto next_tok;
	case VP_STRIFY:
	    // We must expand macros in the body of the stringification
	    // Then, when done, form a final string to return
	    // (it could be used as a include filename, for example, so need the string token)
	    statePush(ps_STRIFY);
	    goto next_tok;
	case VP_SYMBOL:
	case VP_STRING:
	case VP_TEXT: {
	    m_defDepth = 0;
	    if (!m_off) return tok;
	    else goto next_tok;
	}
	case VP_WHITE:		// Handled at top of loop
	case VP_COMMENT:	// Handled at top of loop
	case VP_DEFFORM:	// Handled by state=ps_DEFFORM;
	case VP_DEFVALUE:	// Handled by state=ps_DEFVALUE;
	default:
	    fatalSrc((string)"Internal error: Unexpected token "+tokenName(tok)+"\n");
	    break;
	}
	return tok;
    }
}