bool TemplateSimplifier::simplifyNumericCalculations(Token *tok) { bool ret = false; // (1-2) while (tok->tokAt(4) && tok->next()->isNumber() && tok->tokAt(3)->isNumber()) { // %any% %num% %any% %num% %any% const Token* op = tok->tokAt(2); const Token* after = tok->tokAt(4); if (Token::Match(tok, "* %num% /") && (tok->strAt(3) != "0") && tok->next()->str() == MathLib::multiply(tok->strAt(3), MathLib::divide(tok->next()->str(), tok->strAt(3)))) { // Division where result is a whole number } else if (!((op->str() == "*" && (isLowerThanMulDiv(tok) || tok->str() == "*") && isLowerEqualThanMulDiv(after)) || // associative (Token::Match(op, "[/%]") && isLowerThanMulDiv(tok) && isLowerEqualThanMulDiv(after)) || // NOT associative (Token::Match(op, "[+-]") && isLowerThanMulDiv(tok) && isLowerThanMulDiv(after)) || // Only partially (+) associative, but handled later (Token::Match(op, ">>|<<") && isLowerThanShift(tok) && isLowerThanPlusMinus(after)) || // NOT associative (op->str() == "&" && isLowerThanShift(tok) && isLowerThanShift(after)) || // associative (op->str() == "^" && isLowerThanAnd(tok) && isLowerThanAnd(after)) || // associative (op->str() == "|" && isLowerThanXor(tok) && isLowerThanXor(after)))) // associative break; tok = tok->next(); // Don't simplify "%num% / 0" if (Token::Match(op, "[/%] 0")) continue; // Integer operations if (Token::Match(op, ">>|<<|&|^|%or%")) { const char cop = op->str()[0]; std::string result; if (tok->str().find_first_of("uU") != std::string::npos) result = ShiftUInt(cop, tok, tok->tokAt(2)); else result = ShiftInt(cop, tok, tok->tokAt(2)); if (!result.empty()) { ret = true; tok->str(result); tok->deleteNext(2); continue; } } else if (Token::Match(tok->previous(), "- %num% - %num%")) tok->str(MathLib::add(tok->str(), tok->strAt(2))); else if (Token::Match(tok->previous(), "- %num% + %num%")) tok->str(MathLib::subtract(tok->str(), tok->strAt(2))); else { try { tok->str(MathLib::calculate(tok->str(), tok->strAt(2), op->str()[0])); } catch (InternalError &e) { e.token = tok; throw; } } tok->deleteNext(2); ret = true; } return ret; }
bool TemplateSimplifier::simplifyNumericCalculations(Token *tok) { bool ret = false; // (1-2) while (tok->tokAt(4) && tok->next()->isNumber() && tok->tokAt(3)->isNumber()) { // %any% %num% %any% %num% %any% const Token* op = tok->tokAt(2); const Token* after = tok->tokAt(4); if (Token::Match(tok, "* %num% /") && (tok->strAt(3) != "0") && tok->next()->str() == MathLib::multiply(tok->strAt(3), MathLib::divide(tok->next()->str(), tok->strAt(3)))) { // Division where result is a whole number } else if (!((op->str() == "*" && (isLowerThanMulDiv(tok) || tok->str() == "*") && isLowerEqualThanMulDiv(after)) || // associative (Token::Match(op, "[/%]") && isLowerThanMulDiv(tok) && isLowerEqualThanMulDiv(after)) || // NOT associative (Token::Match(op, "[+-]") && isLowerThanMulDiv(tok) && isLowerThanMulDiv(after)) || // Only partially (+) associative, but handled later (Token::Match(op, ">>|<<") && isLowerThanShift(tok) && isLowerThanPlusMinus(after)) || // NOT associative (op->str() == "&" && isLowerThanShift(tok) && isLowerThanShift(after)) || // associative (op->str() == "^" && isLowerThanAnd(tok) && isLowerThanAnd(after)) || // associative (op->str() == "|" && isLowerThanXor(tok) && isLowerThanXor(after)))) // associative break; tok = tok->next(); // Don't simplify "%num% / 0" if (Token::Match(op, "[/%] 0")) continue; // Integer operations if (Token::Match(op, ">>|<<|&|^|%or%")) { const char cop = op->str()[0]; const MathLib::bigint leftInt(MathLib::toLongNumber(tok->str())); const MathLib::bigint rightInt(MathLib::toLongNumber(tok->strAt(2))); std::string result; if (cop == '&' || cop == '|' || cop == '^') result = MathLib::calculate(tok->str(), tok->strAt(2), cop); else if (cop == '<') { if (tok->previous()->str() != "<<" && rightInt > 0) // Ensure that its not a shift operator as used for streams result = MathLib::toString(leftInt << rightInt); } else if (rightInt > 0) result = MathLib::toString(leftInt >> rightInt); if (!result.empty()) { ret = true; tok->str(result); tok->deleteNext(2); continue; } } else if (Token::Match(tok->previous(), "- %num% - %num%")) tok->str(MathLib::add(tok->str(), tok->strAt(2))); else if (Token::Match(tok->previous(), "- %num% + %num%")) tok->str(MathLib::subtract(tok->str(), tok->strAt(2))); else { try { tok->str(MathLib::calculate(tok->str(), tok->strAt(2), op->str()[0])); } catch (InternalError &e) { e.token = tok; throw; } } tok->deleteNext(2); ret = true; }
static bool isLowerEqualThanMulDiv(const Token* lower) { return isLowerThanMulDiv(lower) || Token::Match(lower, "[*/%]"); }
// TODO: This is not the correct class for simplifyCalculations(), so it // should be moved away. bool TemplateSimplifier::simplifyCalculations(Token *_tokens) { bool ret = false; for (Token *tok = _tokens; tok; tok = tok->next()) { // Remove parentheses around variable.. // keep parentheses here: dynamic_cast<Fred *>(p); // keep parentheses here: A operator * (int); // keep parentheses here: int ( * ( * f ) ( ... ) ) (int) ; // keep parentheses here: int ( * * ( * compilerHookVector ) (void) ) ( ) ; // keep parentheses here: operator new [] (size_t); // keep parentheses here: Functor()(a ... ) // keep parentheses here: ) ( var ) ; if (Token::Match(tok->next(), "( %var% ) ;|)|,|]|%op%") && !tok->isName() && tok->str() != ">" && tok->str() != "]" && !Token::simpleMatch(tok->previous(), "operator") && !Token::simpleMatch(tok->previous(), "* )") && !Token::simpleMatch(tok->previous(), ") )") && !Token::Match(tok->tokAt(-2), "* %var% )") && !Token::Match(tok->tokAt(-2), "%type% ( ) ( %var%") && !Token::Match(tok, ") ( %var% ) ;") ) { tok->deleteNext(); tok = tok->next(); tok->deleteNext(); ret = true; } if (tok->type() == Token::eChar && Token::Match(tok->previous(), "(|&&|%oror% %any% ==|!=|<=|<|>=|> %num% &&|%oror%|)")) { tok->str(MathLib::toString(tok->str()[1] & 0xff)); } if (tok->isNumber()) { // Remove redundant conditions (0&&x) (1||x) if (Token::Match(tok->previous(), "[(=,] 0 &&") || Token::Match(tok->previous(), "[(=,] 1 ||")) { unsigned int par = 0; const Token *tok2 = tok; for (tok2 = tok; tok2; tok2 = tok2->next()) { if (tok2->str() == "(") ++par; else if (tok2->str() == ")") { if (par == 0) break; --par; } else if (par == 0 && (Token::Match(tok2, "[,;]"))) break; } if (Token::Match(tok2, "[);,]")) Token::eraseTokens(tok, tok2); continue; } if (tok->str() == "0") { if (Token::Match(tok->previous(), "[+-|] 0")) { tok = tok->previous(); if (Token::Match(tok->tokAt(-4), "[;{}] %var% = %var% [+-|] 0 ;") && tok->strAt(-3) == tok->previous()->str()) { tok = tok->tokAt(-3); tok->deleteNext(2); tok->deleteThis(); } tok->deleteNext(); tok->deleteThis(); ret = true; } else if (Token::Match(tok->previous(), "[=([,] 0 [+|]") || Token::Match(tok->previous(), "return|case 0 [+|]")) { tok->deleteNext(); tok->deleteThis(); ret = true; } else if (Token::Match(tok->previous(), "[=[(,] 0 * %any% ,|]|)|;|=|%op%") || Token::Match(tok->previous(), "return|case 0 * %any% ,|:|;|=|%op%") || Token::Match(tok->previous(), "return|case 0 && %any% ,|:|;|=|%op%")) { tok->deleteNext(); if (tok->next()->str() == "(") Token::eraseTokens(tok, tok->next()->link()); tok->deleteNext(); ret = true; } else if (Token::Match(tok->previous(), "[=[(,] 0 && *|& %any% ,|]|)|;|=|%op%") || Token::Match(tok->previous(), "return|case 0 && *|& %any% ,|:|;|=|%op%")) { tok->deleteNext(); tok->deleteNext(); if (tok->next()->str() == "(") Token::eraseTokens(tok, tok->next()->link()); tok->deleteNext(); ret = true; } } if (tok->str() == "1") { if (Token::Match(tok->previous(), "[=[(,] 1 %oror% %any% ,|]|)|;|=|%op%") || Token::Match(tok->previous(), "return|case 1 %oror% %any% ,|:|;|=|%op%")) { tok->deleteNext(); if (tok->next()->str() == "(") Token::eraseTokens(tok, tok->next()->link()); tok->deleteNext(); ret = true; } else if (Token::Match(tok->previous(), "[=[(,] 1 %oror% *|& %any% ,|]|)|;|=|%op%") || Token::Match(tok->previous(), "return|case 1 %oror% *|& %any% ,|:|;|=|%op%")) { tok->deleteNext(); tok->deleteNext(); if (tok->next()->str() == "(") Token::eraseTokens(tok, tok->next()->link()); tok->deleteNext(); ret = true; } } if (Token::simpleMatch(tok->previous(), "* 1") || Token::simpleMatch(tok, "1 *")) { if (tok->previous() && tok->previous()->isOp()) tok = tok->previous(); tok->deleteNext(); tok->deleteThis(); ret = true; } // Remove parentheses around number.. if (Token::Match(tok->tokAt(-2), "%any% ( %num% )") && !tok->tokAt(-2)->isName() && tok->strAt(-2) != ">") { tok = tok->previous(); tok->deleteThis(); tok->deleteNext(); ret = true; } if (Token::simpleMatch(tok->previous(), "( 0 ||") || Token::simpleMatch(tok->previous(), "|| 0 )") || Token::simpleMatch(tok->previous(), "( 0 |") || Token::simpleMatch(tok->previous(), "| 0 )") || Token::simpleMatch(tok->previous(), "( 1 &&") || Token::simpleMatch(tok->previous(), "&& 1 )")) { if (tok->previous()->isOp()) tok = tok->previous(); tok->deleteNext(); tok->deleteThis(); ret = true; } if (Token::Match(tok, "%num% ==|!=|<=|>=|<|> %num%") && MathLib::isInt(tok->str()) && MathLib::isInt(tok->strAt(2))) { if (Token::Match(tok->previous(), "(|&&|%oror%") && Token::Match(tok->tokAt(3), ")|&&|%oror%")) { const MathLib::bigint op1(MathLib::toLongNumber(tok->str())); const std::string &cmp(tok->next()->str()); const MathLib::bigint op2(MathLib::toLongNumber(tok->strAt(2))); std::string result; if (cmp == "==") result = (op1 == op2) ? "1" : "0"; else if (cmp == "!=") result = (op1 != op2) ? "1" : "0"; else if (cmp == "<=") result = (op1 <= op2) ? "1" : "0"; else if (cmp == ">=") result = (op1 >= op2) ? "1" : "0"; else if (cmp == "<") result = (op1 < op2) ? "1" : "0"; else if (cmp == ">") result = (op1 > op2) ? "1" : "0"; tok->str(result); tok->deleteNext(2); ret = true; } } } // Division where result is a whole number else if (Token::Match(tok->previous(), "* %num% /") && tok->str() == MathLib::multiply(tok->strAt(2), MathLib::divide(tok->str(), tok->strAt(2)))) { tok->deleteNext(2); } else { // (1-2) while (tok->tokAt(4) && tok->next()->isNumber() && tok->tokAt(3)->isNumber()) { // %any% %num% %any% %num% %any% const Token* op = tok->tokAt(2); const Token* after = tok->tokAt(4); if (Token::Match(tok, "* %num% /") && tok->next()->str() == MathLib::multiply(tok->strAt(3), MathLib::divide(tok->next()->str(), tok->strAt(3)))) { // Division where result is a whole number } else if (!((op->str() == "*" && (isLowerThanMulDiv(tok) || tok->str() == "*") && isLowerEqualThanMulDiv(after)) || // associative (Token::Match(op, "[/%]") && isLowerThanMulDiv(tok) && isLowerEqualThanMulDiv(after)) || // NOT associative (Token::Match(op, "[+-]") && isLowerThanMulDiv(tok) && isLowerThanMulDiv(after)) || // Only partially (+) associative, but handled later (Token::Match(op, ">>|<<") && isLowerThanShift(tok) && isLowerThanPlusMinus(after)) || // NOT associative (op->str() == "&" && isLowerThanShift(tok) && isLowerThanShift(after)) || // associative (op->str() == "^" && isLowerThanAnd(tok) && isLowerThanAnd(after)) || // associative (op->str() == "|" && isLowerThanXor(tok) && isLowerThanXor(after)))) // associative break; tok = tok->next(); // Don't simplify "%num% / 0" if (Token::Match(op, "[/%] 0")) continue; // Integer operations if (Token::Match(op, ">>|<<|&|^|%or%")) { const char cop = op->str()[0]; const MathLib::bigint leftInt(MathLib::toLongNumber(tok->str())); const MathLib::bigint rightInt(MathLib::toLongNumber(tok->strAt(2))); std::string result; if (cop == '&' || cop == '|' || cop == '^') result = MathLib::calculate(tok->str(), tok->strAt(2), cop); else if (cop == '<') { if (tok->previous()->str() != "<<") // Ensure that its not a shift operator as used for streams result = MathLib::toString<MathLib::bigint>(leftInt << rightInt); } else result = MathLib::toString<MathLib::bigint>(leftInt >> rightInt); if (!result.empty()) { ret = true; tok->str(result); tok->deleteNext(2); continue; } } else if (Token::Match(tok->previous(), "- %num% - %num%")) tok->str(MathLib::add(tok->str(), tok->strAt(2))); else if (Token::Match(tok->previous(), "- %num% + %num%")) tok->str(MathLib::subtract(tok->str(), tok->strAt(2))); else { try { tok->str(MathLib::calculate(tok->str(), tok->strAt(2), op->str()[0])); } catch (InternalError &e) { e.token = tok; throw; } } tok->deleteNext(2); ret = true; } } }