hqlcse.cpp 47 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650
  1. /*##############################################################################
  2. Copyright (C) 2011 HPCC Systems.
  3. All rights reserved. This program is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU Affero General Public License as
  5. published by the Free Software Foundation, either version 3 of the
  6. License, or (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU Affero General Public License for more details.
  11. You should have received a copy of the GNU Affero General Public License
  12. along with this program. If not, see <http://www.gnu.org/licenses/>.
  13. ############################################################################## */
  14. #include "platform.h"
  15. #include "jlib.hpp"
  16. #include "jmisc.hpp"
  17. #include "jstream.ipp"
  18. #include "hql.hpp"
  19. #include "hqlcse.ipp"
  20. #include "hqlutil.hpp"
  21. #include "hqlcpputil.hpp"
  22. #include "hqlthql.hpp"
  23. #include "hqlcatom.hpp"
  24. #include "hqlfold.hpp"
  25. #include "hqlpmap.hpp"
  26. #include "hqlopt.hpp"
  27. #include "hqlcerrors.hpp"
  28. #include "hqlttcpp.ipp"
  29. #ifdef _DEBUG
  30. //#define TRACE_CSE
  31. #endif
  32. //The following allows x != y and x == y to be commoned up. It works, but currently disabled
  33. //because cse doesn't preserve short circuit of AND and OR, and some examples mean it will do more
  34. //work because the alias will always be evaluated. (e.g., salt1.xhql)
  35. //Really aliases need to be functional and executed on demand or something similar.
  36. //#define OPTIMIZE_INVERSE
  37. //---------------------------------------------------------------------------
  38. inline bool canWrapWithCSE(IHqlExpression * expr)
  39. {
  40. switch (expr->getOperator())
  41. {
  42. case no_mapto:
  43. return false;
  44. }
  45. return true;
  46. }
  47. bool canCreateTemporary(IHqlExpression * expr)
  48. {
  49. switch (expr->getOperator())
  50. {
  51. case no_range:
  52. case no_rangefrom:
  53. case no_rangeto:
  54. case no_rangecommon:
  55. case no_constant:
  56. case no_all:
  57. case no_mapto:
  58. case no_record:
  59. case no_attr:
  60. case no_attr_expr:
  61. case no_attr_link:
  62. case no_joined:
  63. case no_sizeof:
  64. case no_offsetof:
  65. case no_newtransform:
  66. case no_transform:
  67. case no_assign:
  68. case no_assignall:
  69. case no_left:
  70. case no_right:
  71. case no_self:
  72. case no_top:
  73. case no_activetable:
  74. case no_alias:
  75. case no_skip:
  76. case no_assert:
  77. case no_counter:
  78. case no_sortlist:
  79. case no_matched:
  80. case no_matchtext:
  81. case no_matchunicode:
  82. case no_matchposition:
  83. case no_matchlength:
  84. case no_matchattr:
  85. case no_matchrow:
  86. case no_matchutf8:
  87. case no_recordlist:
  88. case no_transformlist:
  89. case no_rowvalue:
  90. case no_pipe:
  91. case no_colon:
  92. case no_globalscope:
  93. case no_subgraph:
  94. case no_forcelocal:
  95. case no_forcenolocal:
  96. case no_allnodes:
  97. case no_thisnode:
  98. case no_libraryscopeinstance:
  99. case no_loopbody:
  100. return false;
  101. }
  102. return !expr->isAction() && !expr->isTransform();
  103. }
  104. //---------------------------------------------------------------------------
  105. /*
  106. Cse spotting...
  107. * Don't remove named symbols from items that aren't transformed.
  108. * Common items up regardless of the named symbol used to reference it.
  109. */
  110. CseSpotterInfo::CseSpotterInfo(IHqlExpression * expr) : NewTransformInfo(expr)
  111. {
  112. numRefs = 0;
  113. numAssociatedRefs = 0;
  114. alreadyAliased = false;
  115. canAlias = false;
  116. dontTransform = false;
  117. dontTransformSelector = false;
  118. treatAsAliased = false;
  119. inverse = NULL;
  120. annotatedExpr = NULL;
  121. }
  122. //worth aliasing if referenced more than once, and used more than once in the expressions that are going to be evaluated now
  123. bool CseSpotterInfo::worthAliasingOnOwn()
  124. {
  125. return numRefs > 1 && (numRefs != numAssociatedRefs);
  126. }
  127. bool CseSpotterInfo::worthAliasing()
  128. {
  129. if (!inverse)
  130. return worthAliasingOnOwn();
  131. //no_not will always traverse the inverse (at least once), so don't sum the two counts - just use the non inverted count
  132. if (original->getOperator() == no_not)
  133. return worthAliasingOnOwn() || inverse->worthAliasingOnOwn();
  134. if (inverse->original->getOperator() == no_not)
  135. return worthAliasingOnOwn();
  136. unsigned totalRefs = numRefs + inverse->numRefs;
  137. unsigned totalAssociatedRefs = numAssociatedRefs + inverse->numAssociatedRefs;
  138. if ((totalRefs > 1) && (totalRefs != totalAssociatedRefs))
  139. return true;
  140. return false;
  141. }
  142. //Do we create an alias for this node, or the other one?
  143. bool CseSpotterInfo::useInverseForAlias()
  144. {
  145. if (!inverse)
  146. return false;
  147. if (numRefs == numAssociatedRefs)
  148. return true;
  149. node_operator op = original->getOperator();
  150. switch (op)
  151. {
  152. case no_not:
  153. case no_ne:
  154. case no_notin:
  155. case no_notbetween:
  156. return inverse->worthAliasingOnOwn();
  157. }
  158. node_operator invOp = inverse->original->getOperator();
  159. switch (invOp)
  160. {
  161. case no_not: return false; //No otherwise we'll expand recursively!
  162. case no_ne:
  163. case no_notin:
  164. case no_notbetween:
  165. return !worthAliasingOnOwn();
  166. }
  167. return op > invOp;
  168. }
  169. static HqlTransformerInfo cseSpotterInfo("CseSpotter");
  170. CseSpotter::CseSpotter()
  171. : NewHqlTransformer(cseSpotterInfo)
  172. {
  173. canAlias = true;
  174. isAssociated = false;
  175. spottedCandidate = false;
  176. invariantSelector = NULL;
  177. createLocalAliases = false;
  178. createdAlias = false;
  179. }
  180. void CseSpotter::analyseAssociated(IHqlExpression * expr, unsigned pass)
  181. {
  182. isAssociated = true;
  183. analyse(expr, pass);
  184. isAssociated = false;
  185. }
  186. void CseSpotter::analyseExpr(IHqlExpression * expr)
  187. {
  188. CseSpotterInfo * extra = queryBodyExtra(expr);
  189. if (!extra->annotatedExpr && expr->isAnnotation())
  190. extra->annotatedExpr = expr;
  191. if (isAssociated)
  192. extra->numAssociatedRefs++;
  193. node_operator op = expr->getOperator();
  194. #ifdef OPTIMIZE_INVERSE
  195. if (getInverseOp(op) != no_none)
  196. {
  197. OwnedHqlExpr inverse = getInverse(expr);
  198. CseSpotterInfo * inverseExtra = queryBodyExtra(inverse);
  199. extra->inverse = inverseExtra;
  200. inverseExtra->inverse = extra;
  201. }
  202. #endif
  203. if (op == no_alias)
  204. {
  205. queryBodyExtra(expr->queryChild(0))->alreadyAliased = true;
  206. extra->alreadyAliased = true;
  207. }
  208. switch (op)
  209. {
  210. case no_assign:
  211. case no_transform:
  212. case no_newtransform:
  213. case no_range:
  214. case no_rangefrom:
  215. if (expr->isConstant())
  216. return;
  217. break;
  218. case no_constant:
  219. return;
  220. }
  221. if (extra->numRefs++ != 0)
  222. {
  223. if (op == no_alias)
  224. return;
  225. if (!spottedCandidate && extra->worthAliasing())
  226. spottedCandidate = true;
  227. if (canCreateTemporary(expr))
  228. return;
  229. //Ugly! This is here as a temporary hack to stop branches of maps being commoned up and always
  230. //evaluated. The alias spotting and generation really needs to take conditionality into account....
  231. if (op == no_mapto)
  232. return;
  233. }
  234. if (!containsPotentialCSE(expr))
  235. return;
  236. if (canAlias && !expr->isDataset())
  237. extra->canAlias = true;
  238. bool savedCanAlias = canAlias;
  239. if (expr->isDataset() && (op != no_select))// && (op != no_if))
  240. {
  241. //There is little point looking for CSEs within dataset expressions, because only a very small
  242. //minority which would correctly cse, and it can cause lots of problems - e.g., join conditions.
  243. unsigned first = getFirstActivityArgument(expr);
  244. unsigned num = getNumActivityArguments(expr);
  245. HqlExprArray children;
  246. bool defaultCanAlias = canAlias;
  247. ForEachChild(i, expr)
  248. {
  249. IHqlExpression * cur = expr->queryChild(i);
  250. if (i >= first && i < first+num)
  251. canAlias = defaultCanAlias;
  252. else
  253. canAlias = false;
  254. analyseExpr(cur);
  255. }
  256. }
  257. else
  258. PARENT::analyseExpr(expr);
  259. canAlias = savedCanAlias;
  260. }
  261. IHqlExpression * CseSpotter::createAliasOwn(IHqlExpression * expr, CseSpotterInfo * extra)
  262. {
  263. #ifdef TRACE_CSE
  264. StringBuffer s;
  265. DBGLOG("Create alias for %s (%d refs)", getExprIdentifier(s, expr).str(), extra->numRefs);
  266. #endif
  267. extra->alreadyAliased = true;
  268. if (createLocalAliases)
  269. return ::createAliasOwn(expr, createLocalAttribute());
  270. return ::createAliasOwn(expr, NULL);
  271. }
  272. IHqlExpression * CseSpotter::createTransformed(IHqlExpression * expr)
  273. {
  274. node_operator op = expr->getOperator();
  275. switch (op)
  276. {
  277. case no_matched:
  278. case no_matchtext:
  279. case no_matchunicode:
  280. case no_matchposition:
  281. case no_matchlength:
  282. case no_matchrow:
  283. case no_matchutf8:
  284. //These actually go wrong if we remove the named symbols, so traverse under no circumstances.
  285. //others can be traversed to patch up references to datasets that have changed.
  286. case no_translated:
  287. return LINK(expr);
  288. }
  289. OwnedHqlExpr transformed = PARENT::createTransformed(expr);
  290. CseSpotterInfo * splitter = queryBodyExtra(expr);
  291. //MORE: Possibly add a unique number to the alias when this starts worrying about child scopes.
  292. if (splitter->canAlias && splitter->worthAliasing() && checkPotentialCSE(expr, splitter))
  293. {
  294. if (splitter->useInverseForAlias())
  295. {
  296. OwnedHqlExpr inverse = getInverse(expr);
  297. OwnedHqlExpr transformedInverse = transform(inverse);
  298. return getInverse(transformedInverse);
  299. }
  300. createdAlias = true;
  301. //Use the transformed body to ensure that any cses only create a single instance,
  302. //But annotate with first annotation spotted, try and retain the symbols to aid debugging.
  303. LinkedHqlExpr aliasValue = transformed->queryBody();
  304. // if (splitter->annotatedExpr)
  305. // aliasValue.setown(splitter->annotatedExpr->cloneAllAnnotations(aliasValue));
  306. OwnedHqlExpr alias = createAliasOwn(aliasValue.getClear(), splitter);
  307. return alias.getClear();
  308. return expr->cloneAllAnnotations(alias);
  309. }
  310. return transformed.getClear();
  311. }
  312. ANewTransformInfo * CseSpotter::createTransformInfo(IHqlExpression * expr)
  313. {
  314. return CREATE_NEWTRANSFORMINFO(CseSpotterInfo, expr);
  315. }
  316. bool CseSpotter::containsPotentialCSE(IHqlExpression * expr)
  317. {
  318. switch (expr->getOperator())
  319. {
  320. case no_record:
  321. case no_attr:
  322. case no_attr_expr:
  323. case no_attr_link:
  324. case no_joined:
  325. case no_sizeof:
  326. case no_offsetof:
  327. case no_field:
  328. case no_evaluate: // MORE: This is an example of introducing a new scope...
  329. case no_translated: // Causes recursion otherwise....
  330. case no_left:
  331. case no_right:
  332. case no_top:
  333. case no_self:
  334. case no_selfref:
  335. case no_activetable:
  336. case no_filepos:
  337. case no_file_logicalname:
  338. case no_matched:
  339. case no_matchtext:
  340. case no_matchunicode:
  341. case no_matchposition:
  342. case no_matchrow:
  343. case no_matchlength:
  344. case no_matchutf8:
  345. case no_catch:
  346. case no_projectrow:
  347. // case no_evalonce:
  348. return false;
  349. case no_select:
  350. return false; //isNewSelector(expr);
  351. case NO_AGGREGATE:
  352. //There may possibly be cses, but we would need to do lots of scoping analysis to work out whether they were
  353. //really common.
  354. return false;
  355. case no_assign:
  356. case no_assignall:
  357. case no_transform:
  358. case no_newtransform:
  359. case no_range:
  360. case no_rangefrom:
  361. case no_rangeto:
  362. case no_rangecommon:
  363. case no_skip:
  364. return true;
  365. case no_compound_diskread:
  366. case no_compound_indexread:
  367. case no_compound_disknormalize:
  368. case no_compound_diskaggregate:
  369. case no_compound_diskcount:
  370. case no_compound_diskgroupaggregate:
  371. case no_compound_indexnormalize:
  372. case no_compound_indexaggregate:
  373. case no_compound_indexcount:
  374. case no_compound_indexgroupaggregate:
  375. case no_compound_childread:
  376. case no_compound_childnormalize:
  377. case no_compound_childaggregate:
  378. case no_compound_childcount:
  379. case no_compound_childgroupaggregate:
  380. case no_compound_selectnew:
  381. case no_compound_inline:
  382. return false;
  383. #if 0
  384. //Strictly speaking, we shouldn't common up conditional expressions, but it generally provides such a reduction in code
  385. //that it will stay enabled until I come up with a better scheme.
  386. case no_if:
  387. case no_rejected:
  388. case no_which:
  389. case no_case:
  390. case no_map:
  391. return false;
  392. #endif
  393. }
  394. ITypeInfo * type = expr->queryType();
  395. if (type && type->getTypeCode() == type_void)
  396. return false;
  397. return !expr->isConstant();// || expr->isDataset() || expr->isDatarow();
  398. }
  399. bool CseSpotter::checkPotentialCSE(IHqlExpression * expr, CseSpotterInfo * extra)
  400. {
  401. if (extra->alreadyAliased)
  402. return false;
  403. if (!expr->isPure() || !canCreateTemporary(expr))
  404. return false;
  405. if (invariantSelector && exprReferencesDataset(expr, invariantSelector))
  406. return false;
  407. switch (expr->getOperator())
  408. {
  409. case no_eq:
  410. case no_ne:
  411. case no_gt:
  412. case no_ge:
  413. case no_lt:
  414. case no_le:
  415. {
  416. //Don't combine integer comparisons into a CSE - not worth it...
  417. ITypeInfo * type = expr->queryChild(0)->queryType();
  418. switch (type->getTypeCode())
  419. {
  420. case type_boolean:
  421. case type_int:
  422. return false;
  423. }
  424. return true;
  425. }
  426. case no_not:
  427. {
  428. IHqlExpression * child = expr->queryChild(0);
  429. if (queryBodyExtra(child)->isAliased())
  430. return false;
  431. break;
  432. }
  433. case no_charlen:
  434. {
  435. IHqlExpression * child = expr->queryChild(0);
  436. if (queryBodyExtra(child)->isAliased() || child->getOperator() == no_select)
  437. {
  438. type_t tc = child->queryType()->getTypeCode();
  439. switch (tc)
  440. {
  441. case type_varstring:
  442. case type_varunicode:
  443. return true;
  444. }
  445. //prevent (trivial-cast)length(x) from being serialized etc.
  446. extra->treatAsAliased = true;
  447. return false;
  448. }
  449. break;
  450. }
  451. case no_field:
  452. throwUnexpected();
  453. case no_select:
  454. return false; //expr->hasProperty(newAtom);
  455. case no_list:
  456. case no_datasetlist:
  457. case no_getresult: // these are commoned up in the code generator, so don't do it twice.
  458. case no_getgraphresult:
  459. case no_getgraphloopresult:
  460. case no_translated: // Causes recursion otherwise....
  461. case no_random:
  462. return false;
  463. case no_call:
  464. case no_externalcall:
  465. case no_libraryinput:
  466. case no_counter:
  467. return true;
  468. case no_substring:
  469. {
  470. IHqlExpression * child = expr->queryChild(0);
  471. // if (queryBodyExtra(child)->isAliased())
  472. {
  473. SubStringHelper helper(expr);
  474. return !helper.canGenerateInline();
  475. }
  476. return true;
  477. }
  478. case no_cast:
  479. case no_implicitcast:
  480. {
  481. ITypeInfo * exprType = expr->queryType();
  482. if (exprType->getTypeCode() == type_set)
  483. return false;
  484. IHqlExpression * uncast = expr->queryChild(0);
  485. if (uncast->queryValue())
  486. return false;
  487. //Ignore integral casts of items that have already been aliased
  488. if (queryBodyExtra(uncast)->isAliased())
  489. {
  490. if (exprType->isInteger() && uncast->queryType()->isInteger())
  491. {
  492. if (extra->numRefs < 5)
  493. return false;
  494. }
  495. }
  496. break;
  497. }
  498. //Following are all source datasets - no point in commoning them up
  499. //although probably exceptions e.g., table(,pipe)
  500. case no_none:
  501. case no_null:
  502. case no_anon:
  503. case no_pseudods:
  504. case no_all:
  505. // case no_table: - normally work commoning up
  506. case no_temptable:
  507. case no_inlinetable:
  508. case no_xmlproject:
  509. case no_datasetfromrow:
  510. case no_preservemeta:
  511. case no_dataset_alias:
  512. case no_workunit_dataset:
  513. case no_left:
  514. case no_right:
  515. case no_top:
  516. case no_self:
  517. case no_selfref:
  518. case no_keyindex:
  519. case no_newkeyindex:
  520. case no_fail:
  521. case no_activetable:
  522. case no_soapcall:
  523. case no_newsoapcall:
  524. case no_id2blob:
  525. case no_cppbody:
  526. case no_rows:
  527. return false;
  528. }
  529. if (!expr->queryType())
  530. return false;
  531. return (expr->numChildren() > 0);
  532. }
  533. IHqlExpression * CseSpotter::transform(IHqlExpression * expr)
  534. {
  535. return PARENT::transform(expr);
  536. }
  537. IHqlExpression * CseSpotter::queryAlreadyTransformed(IHqlExpression * expr)
  538. {
  539. CseSpotterInfo * extra = queryBodyExtra(expr);
  540. if (extra->dontTransform)
  541. return expr;
  542. IHqlExpression * ret = PARENT::queryAlreadyTransformed(expr);
  543. if (!ret)
  544. {
  545. IHqlExpression * body = expr->queryBody();
  546. if (body != expr)
  547. {
  548. ret = PARENT::queryAlreadyTransformed(body);
  549. if (ret == body)
  550. return NULL;
  551. }
  552. }
  553. return ret;
  554. }
  555. IHqlExpression * CseSpotter::queryAlreadyTransformedSelector(IHqlExpression * expr)
  556. {
  557. CseSpotterInfo * extra = queryBodyExtra(expr);
  558. if (extra->dontTransformSelector)
  559. return expr;
  560. return PARENT::queryAlreadyTransformedSelector(expr);
  561. }
  562. void CseSpotter::stopTransformation(IHqlExpression * expr)
  563. {
  564. IHqlExpression * normalized = expr->queryNormalizedSelector();
  565. queryBodyExtra(expr)->dontTransform = true;
  566. queryBodyExtra(normalized)->dontTransformSelector = true;
  567. }
  568. //---------------------------------------------------------------------------
  569. static HqlTransformerInfo conjunctionTransformerInfo("ConjunctionTransformer");
  570. ConjunctionTransformer::ConjunctionTransformer() : NewHqlTransformer(conjunctionTransformerInfo)
  571. {
  572. }
  573. IHqlExpression * ConjunctionTransformer::createTransformed(IHqlExpression * expr)
  574. {
  575. node_operator op = expr->getOperator();
  576. OwnedHqlExpr transformed;
  577. switch (op)
  578. {
  579. case no_matched:
  580. case no_matchtext:
  581. case no_matchunicode:
  582. case no_matchlength:
  583. case no_matchposition:
  584. case no_matchrow:
  585. case no_matchutf8:
  586. return LINK(expr);
  587. //not so sure why the following causes problems - because the tables get changed I think.
  588. case no_filepos:
  589. case no_file_logicalname:
  590. case no_sizeof:
  591. case no_offsetof:
  592. return LINK(expr);
  593. case no_and:
  594. case no_or:
  595. {
  596. IHqlExpression * left = expr->queryChild(0);
  597. if (left->getOperator() == op)
  598. {
  599. HqlExprArray args, transformedArgs;
  600. left->unwindList(args, op);
  601. ForEachItemIn(i, args)
  602. transformedArgs.append(*transform(&args.item(i)));
  603. transformedArgs.append(*transform(expr->queryChild(1)));
  604. transformed.setown(createLeftBinaryList(op, transformedArgs));
  605. // return expr->cloneAllAnnotations(transformed);
  606. }
  607. break;
  608. }
  609. }
  610. if (!transformed)
  611. transformed.setown(NewHqlTransformer::createTransformed(expr));
  612. return transformed.getClear();
  613. }
  614. //---------------------------------------------------------------------------
  615. #ifdef NEW_CSE_PROCESSING
  616. inline bool canInsertCodeAlias(IHqlExpression * expr)
  617. {
  618. switch (expr->getOperator())
  619. {
  620. case no_range:
  621. case no_rangefrom:
  622. case no_rangeto:
  623. case no_rangecommon:
  624. case no_mapto:
  625. case no_recordlist:
  626. case no_transformlist:
  627. case no_rowvalue:
  628. case no_sortlist:
  629. return false;
  630. default:
  631. return true;
  632. }
  633. }
  634. static HqlTransformerInfo cseScopeTransformerInfo("CseScopeTransformer");
  635. CseScopeTransformer::CseScopeTransformer()
  636. : NewHqlTransformer(cseScopeTransformerInfo)
  637. {
  638. activeParent = NULL;
  639. seq = 0;
  640. conditionDepth = 0;
  641. }
  642. void CseScopeTransformer::analyseExpr(IHqlExpression * expr)
  643. {
  644. expr = expr->queryBody();
  645. if (!containsNonGlobalAlias(expr))
  646. return;
  647. node_operator op = expr->getOperator();
  648. CseScopeInfo * splitter = queryExtra(expr);
  649. if (splitter->seq)
  650. {
  651. splitter->hasSharedParent = true;
  652. splitter->addParent(activeParent);
  653. return;
  654. }
  655. splitter->firstParent = activeParent;
  656. splitter->seq = ++seq;
  657. splitter->isUnconditional = (conditionDepth == 0);
  658. {
  659. IHqlExpression * savedParent = activeParent;
  660. activeParent = expr;
  661. switch (op)
  662. {
  663. case no_if:
  664. case no_or:
  665. case no_and:
  666. case no_case:
  667. {
  668. analyseExpr(expr->queryChild(0));
  669. conditionDepth++;
  670. ForEachChildFrom(i, expr, 1)
  671. analyseExpr(expr->queryChild(i));
  672. conditionDepth--;
  673. break;
  674. }
  675. default:
  676. NewHqlTransformer::analyseExpr(expr);
  677. break;
  678. }
  679. activeParent = savedParent;
  680. }
  681. //Add here so the cse are in the correct order to cope with dependencies...
  682. if (op == no_alias)
  683. {
  684. assertex(!expr->hasProperty(globalAtom));
  685. allCSEs.append(*LINK(splitter));
  686. }
  687. }
  688. bool CseScopeTransformer::attachCSEs(IHqlExpression * root)
  689. {
  690. bool changed = false;
  691. ForEachItemIn(idx, allCSEs)
  692. {
  693. CseScopeInfo& cur = allCSEs.item(idx);
  694. IHqlExpression * aliasLocation = findAliasLocation(&cur);
  695. if (!aliasLocation && cur.isUnconditional)
  696. aliasLocation = root;
  697. if (aliasLocation && aliasLocation != cur.original)
  698. {
  699. queryExtra(aliasLocation)->aliasesToDefine.append(*LINK(cur.original));
  700. changed = true;
  701. }
  702. }
  703. return changed;
  704. }
  705. IHqlExpression * CseScopeTransformer::createTransformed(IHqlExpression * expr)
  706. {
  707. //Can't short-circuit transformation if (!containsAlias(expr)) because it means references to transformed datasets won't get patched up
  708. IHqlExpression * body = expr->queryBody(true);
  709. if (body != expr)
  710. {
  711. OwnedHqlExpr ret = transform(body);
  712. return expr->cloneAnnotation(ret);
  713. }
  714. //slight difference from before...
  715. IHqlExpression * transformed = NewHqlTransformer::createTransformed(expr);
  716. CseScopeInfo * splitter = queryExtra(expr);
  717. if (splitter->aliasesToDefine.ordinality())
  718. {
  719. HqlExprArray args;
  720. args.append(*transformed);
  721. ForEachItemIn(idx, splitter->aliasesToDefine)
  722. {
  723. IHqlExpression * value = &splitter->aliasesToDefine.item(idx);
  724. args.append(*transform(value));
  725. }
  726. if (expr->isDataset())
  727. transformed = createDataset(no_alias_scope, args);
  728. else if (expr->isDatarow())
  729. transformed = createRow(no_alias_scope, args);
  730. else
  731. transformed = createValue(no_alias_scope, transformed->getType(), args);
  732. }
  733. return transformed;
  734. }
  735. ANewTransformInfo * CseScopeTransformer::createTransformInfo(IHqlExpression * expr)
  736. {
  737. return CREATE_NEWTRANSFORMINFO(CseScopeInfo, expr);
  738. }
  739. //First find the highest shared parent node (or this if no parents are shared)
  740. CseScopeInfo * CseScopeTransformer::calcCommonLocation(CseScopeInfo * extra)
  741. {
  742. if (extra->calcedCommonLocation)
  743. return extra->commonLocation;
  744. CseScopeInfo * commonLocation = extra;
  745. if (extra->firstParent)
  746. {
  747. CseScopeInfo * firstParentExtra = queryExtra(extra->firstParent);
  748. CseScopeInfo * commonParent = calcCommonLocation(firstParentExtra);
  749. if ((extra->parents.ordinality() == 0) && (!firstParentExtra->hasSharedParent || extra->firstParent->getOperator() == no_alias))
  750. // if ((extra->parents.ordinality() == 0) && !firstParentExtra->hasSharedParent)
  751. {
  752. //assertex(commonParent == firstParentExtra);
  753. //commonParent = extra;
  754. }
  755. else
  756. {
  757. extra->hasSharedParent = true;
  758. commonLocation = commonParent;
  759. ForEachItemIn(i, extra->parents)
  760. {
  761. CseScopeInfo * nextExtra = calcCommonLocation(queryExtra(extra->parents.item(i)));
  762. if (nextExtra->isUnconditional)
  763. extra->isUnconditional = true;
  764. commonLocation = findCommonPath(commonLocation, nextExtra);
  765. if (!commonLocation && extra->isUnconditional)
  766. break;
  767. }
  768. }
  769. }
  770. else
  771. {
  772. if (extra->hasSharedParent)
  773. commonLocation = NULL;
  774. }
  775. extra->calcedCommonLocation = true;
  776. extra->commonLocation = commonLocation;
  777. return commonLocation;
  778. }
  779. IHqlExpression * CseScopeTransformer::findAliasLocation(CseScopeInfo * extra)
  780. {
  781. CseScopeInfo * best = calcCommonLocation(extra);
  782. loop
  783. {
  784. if (!best)
  785. return NULL;
  786. IHqlExpression * bestLocation = best->original;
  787. if (canInsertCodeAlias(bestLocation))
  788. return bestLocation;
  789. best = selectParent(best);
  790. }
  791. }
  792. CseScopeInfo * CseScopeTransformer::selectParent(CseScopeInfo * info)
  793. {
  794. if (info->hasSharedParent)
  795. return info->commonLocation;
  796. if (!info->firstParent)
  797. return NULL;
  798. return queryExtra(info->firstParent);
  799. }
  800. CseScopeInfo * CseScopeTransformer::findCommonPath(CseScopeInfo * left, CseScopeInfo * right)
  801. {
  802. loop
  803. {
  804. if (!left || !right)
  805. return NULL;
  806. if (left == right)
  807. return left;
  808. if (left->seq > right->seq)
  809. left = selectParent(left);
  810. else
  811. right = selectParent(right);
  812. }
  813. }
  814. #else
  815. CSEentry::CSEentry(IHqlExpression * _value, PathArray & _path)
  816. {
  817. value.set(_value);
  818. unsigned depth=_path.ordinality();
  819. path.ensure(depth);
  820. ForEachItemIn(idx, _path)
  821. path.append(_path.item(idx));
  822. ensurePathValid();
  823. }
  824. void CSEentry::ensurePathValid()
  825. {
  826. //It is not valid to insert a no_code_alias at certain points....
  827. while (path.ordinality())
  828. {
  829. switch (path.tos().getOperator())
  830. {
  831. case no_range:
  832. case no_rangefrom:
  833. case no_rangeto:
  834. case no_rangecommon:
  835. case no_mapto:
  836. case no_recordlist:
  837. case no_transformlist:
  838. case no_rowvalue:
  839. case no_sortlist:
  840. path.pop();
  841. break;
  842. default:
  843. return;
  844. }
  845. }
  846. }
  847. void CSEentry::findCommonPath(PathArray & otherPath)
  848. {
  849. unsigned prevPath = path.ordinality();
  850. unsigned maxPath = path.ordinality();
  851. if (maxPath > otherPath.ordinality())
  852. maxPath = otherPath.ordinality();
  853. unsigned idx;
  854. for (idx = 0; idx < maxPath; idx++)
  855. {
  856. IHqlExpression * l = &path.item(idx);
  857. IHqlExpression * r = &otherPath.item(idx);
  858. if (l != r)
  859. break;
  860. }
  861. //Ensure the new location is valid for receiving the CSE
  862. while (idx != 0)
  863. {
  864. if (canWrapWithCSE(&path.item(idx-1)))
  865. break;
  866. idx--;
  867. }
  868. path.trunc(idx);
  869. if (prevPath != path.ordinality())
  870. {
  871. ForEachItemIn(idx2, dependsOn)
  872. dependsOn.item(idx2).findCommonPath(path);
  873. }
  874. ensurePathValid();
  875. }
  876. static HqlTransformerInfo cseScopeTransformerInfo("CseScopeTransformer");
  877. CseScopeTransformer::CseScopeTransformer()
  878. : NewHqlTransformer(cseScopeTransformerInfo)
  879. {
  880. }
  881. void CseScopeTransformer::analyseExpr(IHqlExpression * expr)
  882. {
  883. expr = expr->queryBody();
  884. if (!containsNonGlobalAlias(expr))
  885. return;
  886. CSEentry * cse = NULL;
  887. node_operator op = expr->getOperator();
  888. if (op == no_alias)
  889. {
  890. assertex(!expr->hasProperty(globalAtom));
  891. CseScopeInfo * splitter = queryExtra(expr);
  892. //PrintLog("splitter: %s", expr->toString(StringBuffer()).str());
  893. if (splitter->cseUse)
  894. {
  895. //Find the common path, and map the alias.
  896. CSEentry * cse = splitter->cseUse;
  897. cse->findCommonPath(path);
  898. if (activeCSE.ordinality())
  899. activeCSE.tos().dependsOn.append(*LINK(cse));
  900. return;
  901. }
  902. cse = new CSEentry(expr, path);
  903. splitter->cseUse.setown(cse);
  904. if (activeCSE.ordinality())
  905. activeCSE.tos().dependsOn.append(*LINK(cse));
  906. activeCSE.append(*LINK(cse));
  907. }
  908. #if 0
  909. if ((op == no_transform) || (op == no_newtransform))
  910. {
  911. //For a transform add each assignment as a path point - so the aliases for assignments don't end up
  912. //before aliases for skip attributes.
  913. path.append(*expr);
  914. ForEachChild(i, expr)
  915. {
  916. IHqlExpression * cur = expr->queryChild(i);
  917. analyseExpr(cur);
  918. path.append(*cur);
  919. }
  920. ForEachChild(i2, expr)
  921. path.pop();
  922. path.pop();
  923. }
  924. else
  925. #endif
  926. {
  927. path.append(*expr);
  928. NewHqlTransformer::analyseExpr(expr);
  929. path.pop();
  930. }
  931. //Add here so the cse are in the correct order to cope with dependencies...
  932. if (cse)
  933. {
  934. allCSEs.append(*LINK(cse));
  935. activeCSE.pop();
  936. }
  937. }
  938. bool CseScopeTransformer::attachCSEs(IHqlExpression * /*root*/)
  939. {
  940. bool changed = false;
  941. ForEachItemIn(idx, allCSEs)
  942. {
  943. CSEentry & cur = allCSEs.item(idx);
  944. if (cur.path.ordinality())
  945. {
  946. IHqlExpression & location = cur.path.tos();
  947. queryExtra(&location)->cseDefine.append(OLINK(cur));
  948. changed = true;
  949. }
  950. }
  951. return changed;
  952. }
  953. IHqlExpression * CseScopeTransformer::createTransformed(IHqlExpression * expr)
  954. {
  955. //Can't short-circuit transformation if (!containsAlias(expr)) because it means references to transformed datasets won't get patched up
  956. IHqlExpression * body = expr->queryBody(true);
  957. if (body != expr)
  958. {
  959. OwnedHqlExpr ret = transform(body);
  960. return expr->cloneAnnotation(ret);
  961. }
  962. //slight difference from before...
  963. IHqlExpression * transformed = NewHqlTransformer::createTransformed(expr);
  964. CseScopeInfo * splitter = queryExtra(expr);
  965. if (splitter->cseDefine.ordinality())
  966. {
  967. HqlExprArray args;
  968. args.append(*transformed);
  969. ForEachItemIn(idx, splitter->cseDefine)
  970. {
  971. CSEentry & cur = splitter->cseDefine.item(idx);
  972. args.append(*transform(cur.value));
  973. }
  974. if (expr->isDataset())
  975. transformed = createDataset(no_alias_scope, args);
  976. else if (expr->isDatarow())
  977. transformed = createRow(no_alias_scope, args);
  978. else
  979. transformed = createValue(no_alias_scope, transformed->getType(), args);
  980. }
  981. return transformed;
  982. }
  983. ANewTransformInfo * CseScopeTransformer::createTransformInfo(IHqlExpression * expr)
  984. {
  985. return CREATE_NEWTRANSFORMINFO(CseScopeInfo, expr);
  986. }
  987. #endif
  988. IHqlExpression * spotScalarCSE(IHqlExpression * expr, IHqlExpression * limit)
  989. {
  990. if (expr->isConstant())
  991. return LINK(expr);
  992. switch (expr->getOperator())
  993. {
  994. case no_select:
  995. if (!expr->hasProperty(newAtom))
  996. return LINK(expr);
  997. break;
  998. }
  999. OwnedHqlExpr transformed = LINK(expr); //removeNamedSymbols(expr);
  1000. bool addedAliases = false;
  1001. //First spot the aliases - so that restructuring the ands doesn't lose any existing aliases.
  1002. {
  1003. CseSpotter spotter;
  1004. spotter.analyse(transformed, 0);
  1005. if (spotter.foundCandidates())
  1006. {
  1007. if (limit)
  1008. spotter.stopTransformation(limit);
  1009. transformed.setown(spotter.transformRoot(transformed));
  1010. addedAliases = spotter.createdNewAliases();
  1011. }
  1012. }
  1013. if (!containsAlias(transformed))
  1014. return transformed.getClear();
  1015. //Transform conjunctions so they are (a AND (b AND (c AND d))) not (((a AND b) AND c) AND d)
  1016. //so that alias scope can be introduced in a better place.
  1017. {
  1018. ConjunctionTransformer tr;
  1019. transformed.setown(tr.transformRoot(transformed));
  1020. }
  1021. if (!addedAliases)
  1022. return transformed.getClear();
  1023. //Now work out where in the tree the aliases should be evaluated.
  1024. {
  1025. CseScopeTransformer scoper;
  1026. scoper.analyse(transformed, 0);
  1027. if (scoper.attachCSEs(transformed))
  1028. transformed.setown(scoper.transformRoot(transformed));
  1029. }
  1030. return transformed.getClear();
  1031. }
  1032. void spotScalarCSE(SharedHqlExpr & expr, SharedHqlExpr & associated, IHqlExpression * limit, IHqlExpression * invariantSelector)
  1033. {
  1034. CseSpotter spotter;
  1035. spotter.analyse(expr, 0);
  1036. if (associated)
  1037. spotter.analyseAssociated(associated, 0);
  1038. if (!spotter.foundCandidates())
  1039. return;
  1040. if (limit)
  1041. spotter.stopTransformation(limit);
  1042. if (invariantSelector)
  1043. spotter.setInvariantSelector(invariantSelector);
  1044. expr.setown(spotter.transformRoot(expr));
  1045. associated.setown(spotter.transformRoot(associated));
  1046. }
  1047. void spotScalarCSE(HqlExprArray & exprs, HqlExprArray & associated, IHqlExpression * limit, IHqlExpression * invariantSelector)
  1048. {
  1049. CseSpotter spotter;
  1050. spotter.analyseArray(exprs, 0);
  1051. ForEachItemIn(ia, associated)
  1052. spotter.analyseAssociated(&associated.item(ia), 0);
  1053. if (!spotter.foundCandidates())
  1054. return;
  1055. if (limit)
  1056. spotter.stopTransformation(limit);
  1057. if (invariantSelector)
  1058. spotter.setInvariantSelector(invariantSelector);
  1059. HqlExprArray newExprs;
  1060. HqlExprArray newAssociated;
  1061. spotter.transformRoot(exprs, newExprs);
  1062. spotter.transformRoot(associated, newAssociated);
  1063. replaceArray(exprs, newExprs);
  1064. replaceArray(associated, newAssociated);
  1065. }
  1066. //---------------------------------------------------------------------------
  1067. //The TableInvariantTransformer is important for ensuring that getResultXXX code is executed in the code context, amongst other things
  1068. //It must ensure that any global aliases couldn't contain some other global aliases inside a child query, otherwise when the child query is
  1069. //evaluated the result won't be in the correct place.
  1070. //
  1071. //MORE: This could be improved to work out whether it is worth creating an alias (which will then be serialized...)
  1072. //e.g., don't alias i) <alias<n>> +- offset or ii) extension of an alias's size., iii) substring of a fixed size string. iv) length(string
  1073. //however it is pretty good as it stands.
  1074. //ideally it would need information about how many times the expression is likely to be evaluated (e.g., 1/many)
  1075. //so that could be taken into account (e.g, filenames which are 'string' + conditional)
  1076. static bool canHoistInvariant(IHqlExpression * expr)
  1077. {
  1078. if (!canCreateTemporary(expr))
  1079. {
  1080. if ((expr->getOperator() != no_alias) || expr->hasProperty(globalAtom))
  1081. return false;
  1082. }
  1083. if (!expr->isPure())
  1084. return false;
  1085. switch (expr->getOperator())
  1086. {
  1087. case no_list:
  1088. case no_datasetlist:
  1089. return false; // probably don't want to hoist these
  1090. }
  1091. return true;
  1092. }
  1093. static HqlTransformerInfo tableInvariantTransformerInfo("TableInvariantTransformer");
  1094. TableInvariantTransformer::TableInvariantTransformer() : NewHqlTransformer(tableInvariantTransformerInfo)
  1095. {
  1096. canAlias = true;
  1097. }
  1098. bool TableInvariantTransformer::isInvariant(IHqlExpression * expr)
  1099. {
  1100. TableInvariantInfo * extra = queryBodyExtra(expr);
  1101. if (extra->cachedInvariant)
  1102. return extra->isInvariant;
  1103. bool invariant = false;
  1104. node_operator op = expr->getOperator();
  1105. switch (op)
  1106. {
  1107. case no_record:
  1108. case no_null:
  1109. case no_activetable:
  1110. case no_activerow:
  1111. case no_left:
  1112. case no_right:
  1113. case no_self:
  1114. case no_top:
  1115. case no_selfref:
  1116. case no_filepos:
  1117. case no_file_logicalname:
  1118. case no_joined:
  1119. case no_offsetof:
  1120. case no_sizeof:
  1121. case NO_AGGREGATE:
  1122. break;
  1123. case no_preservemeta:
  1124. invariant = isInvariant(expr->queryChild(0));
  1125. break;
  1126. case no_constant:
  1127. case no_workunit_dataset:
  1128. case no_getresult:
  1129. case no_getgraphresult:
  1130. invariant = true;
  1131. break;
  1132. case no_select:
  1133. {
  1134. IHqlExpression * ds = expr->queryChild(0);
  1135. if ((expr->hasProperty(newAtom) || ds->isDatarow()) && !expr->isDataset())
  1136. invariant = isInvariant(ds);
  1137. break;
  1138. }
  1139. case no_newaggregate:
  1140. {
  1141. //Allow these on a very strict subset of the datasets - to ensure that no potential globals can be included in the dataset
  1142. if (!isInvariant(expr->queryChild(0)))
  1143. break;
  1144. switch (querySimpleAggregate(expr, false, true))
  1145. {
  1146. case no_existsgroup:
  1147. case no_countgroup:
  1148. invariant = true;
  1149. break;
  1150. }
  1151. break;
  1152. }
  1153. case no_selectnth:
  1154. switch (expr->queryChild(1)->getOperator())
  1155. {
  1156. case no_constant:
  1157. case no_counter:
  1158. invariant = isInvariant(expr->queryChild(0));
  1159. break;
  1160. }
  1161. break;
  1162. default:
  1163. if (!isContextDependent(expr))
  1164. {
  1165. if (!expr->isAction())// && !expr->isDataset() && !expr->isDatarow())
  1166. {
  1167. invariant = true;
  1168. ForEachChild(i, expr)
  1169. {
  1170. IHqlExpression * cur = expr->queryChild(i);
  1171. if (!isInvariant(cur))
  1172. {
  1173. invariant = false;
  1174. break;
  1175. }
  1176. }
  1177. }
  1178. }
  1179. break;
  1180. }
  1181. extra->cachedInvariant = true;
  1182. extra->isInvariant = invariant;
  1183. return invariant;
  1184. }
  1185. #if 0
  1186. void TableInvariantTransformer::analyseExpr(IHqlExpression * expr)
  1187. {
  1188. expr = expr->queryBody();
  1189. if (alreadyVisited(expr))
  1190. return;
  1191. node_operator op = expr->getOperator();
  1192. switch (op)
  1193. {
  1194. case no_record:
  1195. case no_constant:
  1196. return;
  1197. }
  1198. if (isInvariant(expr) && !expr->isAttribute() && !expr->isConstant() && canHoistInvariant(expr))
  1199. {
  1200. TableInvariantInfo * extra = queryBodyExtra(expr);
  1201. if (op == no_alias)
  1202. {
  1203. if (!expr->hasProperty(globalAtom))
  1204. extra->createAlias = true;
  1205. }
  1206. else
  1207. extra->createAlias = true;
  1208. return;
  1209. }
  1210. if (op == no_attr_expr)
  1211. analyseChildren(expr);
  1212. else
  1213. NewHqlTransformer::analyseExpr(expr);
  1214. }
  1215. #else
  1216. void TableInvariantTransformer::analyseExpr(IHqlExpression * expr)
  1217. {
  1218. expr = expr->queryBody();
  1219. TableInvariantInfo * extra = queryBodyExtra(expr);
  1220. if (alreadyVisited(expr))
  1221. return;
  1222. //More - these need to be handled properly...
  1223. node_operator op = expr->getOperator();
  1224. switch (op)
  1225. {
  1226. case no_record:
  1227. case no_constant:
  1228. return;
  1229. }
  1230. //We are trying to ensure that any expressions that don't access fields that are dependent on the activeDatasets/context are only
  1231. //evaluated once => check for active dataset rather than any dataset
  1232. bool candidate = false;
  1233. if (!isContextDependent(expr) && !expr->isAttribute())
  1234. {
  1235. if (isInlineTrivialDataset(expr) && !expr->isConstant())
  1236. {
  1237. candidate = (op != no_null);
  1238. }
  1239. else
  1240. {
  1241. if (!containsActiveDataset(expr))
  1242. {
  1243. //MORE: We should be able to hoist constant datasets (e.g., temptables), but it causes problems
  1244. //e.g., stops items it contains from being aliased. So
  1245. if (!expr->isAction() && !expr->isDataset() && !expr->isDatarow())
  1246. {
  1247. switch (op)
  1248. {
  1249. case no_alias:
  1250. if (!expr->hasProperty(globalAtom))
  1251. extra->createAlias = true;
  1252. return;
  1253. default:
  1254. //MORE: We should be able to hoist constant datasets (e.g., temptables), but it causes problems
  1255. //e.g., stops items it contains from being aliased.
  1256. candidate = !expr->isConstant();
  1257. break;
  1258. }
  1259. }
  1260. }
  1261. }
  1262. if (candidate && canHoistInvariant(expr))
  1263. {
  1264. extra->createAlias = true;
  1265. return;
  1266. }
  1267. }
  1268. if (op == no_attr_expr)
  1269. analyseChildren(expr);
  1270. else
  1271. NewHqlTransformer::analyseExpr(expr);
  1272. }
  1273. #endif
  1274. bool TableInvariantTransformer::isAlwaysAlias(IHqlExpression * expr)
  1275. {
  1276. if (queryBodyExtra(expr)->createAlias)
  1277. return true;
  1278. switch (expr->getOperator())
  1279. {
  1280. case no_alias:
  1281. case no_getresult: // these are commoned up in the code generator, so don't do it twice.
  1282. case no_getgraphresult:
  1283. case no_getgraphloopresult:
  1284. return true;
  1285. }
  1286. return false;
  1287. }
  1288. bool TableInvariantTransformer::isTrivialAlias(IHqlExpression * expr)
  1289. {
  1290. switch (expr->getOperator())
  1291. {
  1292. case no_cast:
  1293. case no_implicitcast:
  1294. //Don't create aliases for items that are simply integral casts of other aliases.
  1295. {
  1296. ITypeInfo * type = expr->queryType();
  1297. if (type->isInteger())
  1298. {
  1299. IHqlExpression * cast = expr->queryChild(0);
  1300. ITypeInfo * castType = cast->queryType();
  1301. if (castType->isInteger() && isAlwaysAlias(cast))
  1302. {
  1303. switch (type->getSize())
  1304. {
  1305. case 1: case 2: case 4: case 8:
  1306. return true;
  1307. }
  1308. }
  1309. }
  1310. break;
  1311. }
  1312. case no_not:
  1313. {
  1314. IHqlExpression * child = expr->queryChild(0);
  1315. if (isAlwaysAlias(child))
  1316. return true;
  1317. break;
  1318. }
  1319. }
  1320. return false;
  1321. }
  1322. IHqlExpression * TableInvariantTransformer::createTransformed(IHqlExpression * expr)
  1323. {
  1324. if (expr->getOperator() == no_alias)
  1325. {
  1326. OwnedHqlExpr newChild = transform(expr->queryChild(0));
  1327. if (newChild->getOperator() == no_alias)
  1328. return newChild.getClear();
  1329. }
  1330. OwnedHqlExpr transformed = NewHqlTransformer::createTransformed(expr);
  1331. if (queryBodyExtra(expr)->createAlias)
  1332. {
  1333. if (!isTrivialAlias(expr))
  1334. {
  1335. OwnedHqlExpr attr = createAttribute(globalAtom);
  1336. if (transformed->getOperator() == no_alias)
  1337. transformed.set(transformed->queryChild(0));
  1338. return createAlias(transformed->queryBody(), attr);
  1339. }
  1340. }
  1341. return transformed.getClear();
  1342. }
  1343. //---------------------------------------------------------------------------
  1344. IHqlExpression * spotTableInvariant(IHqlExpression * expr)
  1345. {
  1346. TableInvariantTransformer transformer;
  1347. transformer.analyse(expr, 0);
  1348. return transformer.transformRoot(expr);
  1349. }
  1350. IHqlExpression * spotTableInvariantChildren(IHqlExpression * expr)
  1351. {
  1352. TableInvariantTransformer transformer;
  1353. ForEachChild(i1, expr)
  1354. transformer.analyse(expr->queryChild(i1), 0);
  1355. return transformer.transformRoot(expr);
  1356. }
  1357. //---------------------------------------------------------------------------
  1358. static HqlTransformerInfo globalAliasTransformerInfo("GlobalAliasTransformer");
  1359. GlobalAliasTransformer::GlobalAliasTransformer() : NewHqlTransformer(globalAliasTransformerInfo)
  1360. {
  1361. insideGlobal = false;
  1362. }
  1363. void GlobalAliasTransformer::analyseExpr(IHqlExpression * expr)
  1364. {
  1365. if (!containsAlias(expr))
  1366. return;
  1367. bool wasInsideGlobal = insideGlobal;
  1368. GlobalAliasInfo * extra = queryBodyExtra(expr);
  1369. extra->numUses++;
  1370. if (expr->getOperator() == no_alias)
  1371. {
  1372. if (expr->hasProperty(globalAtom))
  1373. {
  1374. // assertex(!containsActiveDataset(expr) || isInlineTrivialDataset(expr));
  1375. if (!insideGlobal)
  1376. extra->isOuter = true;
  1377. }
  1378. if (extra->numUses > 1)
  1379. return;
  1380. if (extra->isOuter)
  1381. insideGlobal = true;
  1382. }
  1383. else
  1384. {
  1385. //ugly, but we need to walk children more than once even if we've already been here.
  1386. //What is important is if visited >1 or occur globally, so can short circuit based on that condition.
  1387. //This currently links too many times because subsequent cse generation may common up multiple uses of the same item
  1388. //but it's not too bad.
  1389. //We could rerun this again if that was a major issue.
  1390. if (insideGlobal)
  1391. {
  1392. if (extra->numUses > 2)
  1393. return; // may need to visit children more than once so that alias is linked twice.
  1394. }
  1395. else
  1396. {
  1397. if (extra->isOuter && (extra->numUses > 2))
  1398. return;
  1399. extra->isOuter = true;
  1400. }
  1401. }
  1402. if (expr->getOperator() == no_attr_expr)
  1403. analyseChildren(expr);
  1404. else
  1405. NewHqlTransformer::analyseExpr(expr);
  1406. insideGlobal = wasInsideGlobal;
  1407. }
  1408. IHqlExpression * GlobalAliasTransformer::createTransformed(IHqlExpression * expr)
  1409. {
  1410. OwnedHqlExpr transformed = NewHqlTransformer::createTransformed(expr);
  1411. if ((expr->getOperator() == no_alias))
  1412. {
  1413. GlobalAliasInfo * extra = queryBodyExtra(expr);
  1414. if (expr->hasProperty(globalAtom))
  1415. {
  1416. if (!extra->isOuter)
  1417. {
  1418. if (extra->numUses == 1)
  1419. return LINK(transformed->queryChild(0));
  1420. if (!expr->hasProperty(localAtom))
  1421. return appendLocalAttribute(transformed);
  1422. }
  1423. else if (expr->hasProperty(localAtom))
  1424. {
  1425. //Should never occur - but just about conceivable that some kind of constant folding
  1426. //might cause a surrounding global alias to be removed.
  1427. return removeLocalAttribute(transformed);
  1428. }
  1429. }
  1430. else
  1431. {
  1432. if ((extra->numUses == 1) && !expr->hasProperty(internalAtom))
  1433. return LINK(transformed->queryChild(0));
  1434. }
  1435. }
  1436. return transformed.getClear();
  1437. }
  1438. //---------------------------------------------------------------------------
  1439. IHqlExpression * optimizeActivityAliasReferences(IHqlExpression * expr)
  1440. {
  1441. if (!containsAlias(expr))
  1442. return LINK(expr);
  1443. unsigned first = getFirstActivityArgument(expr);
  1444. unsigned last = first + getNumActivityArguments(expr);
  1445. bool foundAlias = false;
  1446. ForEachChild(i1, expr)
  1447. {
  1448. IHqlExpression * cur = expr->queryChild(i1);
  1449. if (((i1 < first) || (i1 >= last)) && containsAlias(cur))
  1450. {
  1451. foundAlias = true;
  1452. break;
  1453. }
  1454. }
  1455. if (!foundAlias)
  1456. return LINK(expr);
  1457. GlobalAliasTransformer transformer;
  1458. ForEachChild(i2, expr)
  1459. {
  1460. IHqlExpression * cur = expr->queryChild(i2);
  1461. if (((i2 < first) || (i2 >= last)) && containsAlias(cur))
  1462. transformer.analyse(cur, 0);
  1463. }
  1464. HqlExprArray args;
  1465. ForEachChild(i3, expr)
  1466. {
  1467. IHqlExpression * cur = expr->queryChild(i3);
  1468. if ((i3 < first) || (i3 >= last))
  1469. args.append(*transformer.transformRoot(cur));
  1470. else
  1471. args.append(*LINK(cur));
  1472. }
  1473. return cloneOrLink(expr, args);
  1474. }