hqlcse.cpp 47 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654
  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. //MORE: ds[n].x would probably be worth cseing.
  455. return false;
  456. case no_list:
  457. case no_datasetlist:
  458. case no_getresult: // these are commoned up in the code generator, so don't do it twice.
  459. case no_getgraphresult:
  460. case no_getgraphloopresult:
  461. case no_translated: // Causes recursion otherwise....
  462. case no_random:
  463. return false;
  464. case no_call:
  465. case no_externalcall:
  466. case no_libraryinput:
  467. case no_counter:
  468. return true;
  469. case no_substring:
  470. {
  471. IHqlExpression * child = expr->queryChild(0);
  472. // if (queryBodyExtra(child)->isAliased())
  473. {
  474. SubStringHelper helper(expr);
  475. return !helper.canGenerateInline();
  476. }
  477. return true;
  478. }
  479. case no_cast:
  480. case no_implicitcast:
  481. {
  482. ITypeInfo * exprType = expr->queryType();
  483. if (exprType->getTypeCode() == type_set)
  484. return false;
  485. IHqlExpression * uncast = expr->queryChild(0);
  486. if (uncast->queryValue())
  487. return false;
  488. //Ignore integral casts of items that have already been aliased
  489. if (queryBodyExtra(uncast)->isAliased())
  490. {
  491. if (exprType->isInteger() && uncast->queryType()->isInteger())
  492. {
  493. if (extra->numRefs < 5)
  494. return false;
  495. }
  496. }
  497. break;
  498. }
  499. //Following are all source datasets - no point in commoning them up
  500. //although probably exceptions e.g., table(,pipe)
  501. case no_none:
  502. case no_null:
  503. case no_anon:
  504. case no_pseudods:
  505. case no_all:
  506. // case no_table: - normally work commoning up
  507. case no_temptable:
  508. case no_inlinetable:
  509. case no_xmlproject:
  510. case no_datasetfromrow:
  511. case no_preservemeta:
  512. case no_dataset_alias:
  513. case no_workunit_dataset:
  514. case no_left:
  515. case no_right:
  516. case no_top:
  517. case no_self:
  518. case no_selfref:
  519. case no_keyindex:
  520. case no_newkeyindex:
  521. case no_fail:
  522. case no_activetable:
  523. case no_soapcall:
  524. case no_newsoapcall:
  525. case no_id2blob:
  526. case no_cppbody:
  527. case no_rows:
  528. return false;
  529. }
  530. if (!expr->queryType())
  531. return false;
  532. return (expr->numChildren() > 0);
  533. }
  534. IHqlExpression * CseSpotter::transform(IHqlExpression * expr)
  535. {
  536. return PARENT::transform(expr);
  537. }
  538. IHqlExpression * CseSpotter::queryAlreadyTransformed(IHqlExpression * expr)
  539. {
  540. CseSpotterInfo * extra = queryBodyExtra(expr);
  541. if (extra->dontTransform)
  542. return expr;
  543. IHqlExpression * ret = PARENT::queryAlreadyTransformed(expr);
  544. if (!ret)
  545. {
  546. IHqlExpression * body = expr->queryBody();
  547. if (body != expr)
  548. {
  549. ret = PARENT::queryAlreadyTransformed(body);
  550. if (ret == body)
  551. return NULL;
  552. }
  553. }
  554. return ret;
  555. }
  556. IHqlExpression * CseSpotter::queryAlreadyTransformedSelector(IHqlExpression * expr)
  557. {
  558. CseSpotterInfo * extra = queryBodyExtra(expr);
  559. if (extra->dontTransformSelector)
  560. return expr;
  561. return PARENT::queryAlreadyTransformedSelector(expr);
  562. }
  563. void CseSpotter::stopTransformation(IHqlExpression * expr)
  564. {
  565. IHqlExpression * normalized = expr->queryNormalizedSelector();
  566. queryBodyExtra(expr)->dontTransform = true;
  567. queryBodyExtra(normalized)->dontTransformSelector = true;
  568. }
  569. //---------------------------------------------------------------------------
  570. static HqlTransformerInfo conjunctionTransformerInfo("ConjunctionTransformer");
  571. ConjunctionTransformer::ConjunctionTransformer() : NewHqlTransformer(conjunctionTransformerInfo)
  572. {
  573. }
  574. IHqlExpression * ConjunctionTransformer::createTransformed(IHqlExpression * expr)
  575. {
  576. node_operator op = expr->getOperator();
  577. OwnedHqlExpr transformed;
  578. switch (op)
  579. {
  580. case no_matched:
  581. case no_matchtext:
  582. case no_matchunicode:
  583. case no_matchlength:
  584. case no_matchposition:
  585. case no_matchrow:
  586. case no_matchutf8:
  587. return LINK(expr);
  588. //not so sure why the following causes problems - because the tables get changed I think.
  589. case no_filepos:
  590. case no_file_logicalname:
  591. case no_sizeof:
  592. case no_offsetof:
  593. return LINK(expr);
  594. case no_and:
  595. case no_or:
  596. {
  597. IHqlExpression * left = expr->queryChild(0);
  598. if (left->getOperator() == op)
  599. {
  600. HqlExprArray args, transformedArgs;
  601. left->unwindList(args, op);
  602. ForEachItemIn(i, args)
  603. transformedArgs.append(*transform(&args.item(i)));
  604. transformedArgs.append(*transform(expr->queryChild(1)));
  605. transformed.setown(createLeftBinaryList(op, transformedArgs));
  606. // return expr->cloneAllAnnotations(transformed);
  607. }
  608. break;
  609. }
  610. }
  611. if (!transformed)
  612. transformed.setown(NewHqlTransformer::createTransformed(expr));
  613. return transformed.getClear();
  614. }
  615. //---------------------------------------------------------------------------
  616. #ifdef NEW_CSE_PROCESSING
  617. inline bool canInsertCodeAlias(IHqlExpression * expr)
  618. {
  619. switch (expr->getOperator())
  620. {
  621. case no_range:
  622. case no_rangefrom:
  623. case no_rangeto:
  624. case no_rangecommon:
  625. case no_mapto:
  626. case no_recordlist:
  627. case no_transformlist:
  628. case no_rowvalue:
  629. case no_sortlist:
  630. return false;
  631. default:
  632. return true;
  633. }
  634. }
  635. static HqlTransformerInfo cseScopeTransformerInfo("CseScopeTransformer");
  636. CseScopeTransformer::CseScopeTransformer()
  637. : NewHqlTransformer(cseScopeTransformerInfo)
  638. {
  639. activeParent = NULL;
  640. seq = 0;
  641. conditionDepth = 0;
  642. }
  643. void CseScopeTransformer::analyseExpr(IHqlExpression * expr)
  644. {
  645. expr = expr->queryBody();
  646. if (!containsNonGlobalAlias(expr))
  647. return;
  648. node_operator op = expr->getOperator();
  649. CseScopeInfo * splitter = queryExtra(expr);
  650. if (splitter->seq)
  651. {
  652. splitter->hasSharedParent = true;
  653. splitter->addParent(activeParent);
  654. return;
  655. }
  656. splitter->firstParent = activeParent;
  657. splitter->seq = ++seq;
  658. splitter->isUnconditional = (conditionDepth == 0);
  659. {
  660. IHqlExpression * savedParent = activeParent;
  661. activeParent = expr;
  662. switch (op)
  663. {
  664. case no_if:
  665. case no_or:
  666. case no_and:
  667. case no_case:
  668. {
  669. analyseExpr(expr->queryChild(0));
  670. conditionDepth++;
  671. ForEachChildFrom(i, expr, 1)
  672. analyseExpr(expr->queryChild(i));
  673. conditionDepth--;
  674. break;
  675. }
  676. default:
  677. NewHqlTransformer::analyseExpr(expr);
  678. break;
  679. }
  680. activeParent = savedParent;
  681. }
  682. //Add here so the cse are in the correct order to cope with dependencies...
  683. if (op == no_alias)
  684. {
  685. assertex(!expr->hasProperty(globalAtom));
  686. allCSEs.append(*LINK(splitter));
  687. }
  688. }
  689. bool CseScopeTransformer::attachCSEs(IHqlExpression * root)
  690. {
  691. bool changed = false;
  692. ForEachItemIn(idx, allCSEs)
  693. {
  694. CseScopeInfo& cur = allCSEs.item(idx);
  695. IHqlExpression * aliasLocation = findAliasLocation(&cur);
  696. if (!aliasLocation && cur.isUnconditional)
  697. aliasLocation = root;
  698. if (aliasLocation && aliasLocation != cur.original)
  699. {
  700. queryExtra(aliasLocation)->aliasesToDefine.append(*LINK(cur.original));
  701. changed = true;
  702. }
  703. }
  704. return changed;
  705. }
  706. IHqlExpression * CseScopeTransformer::createTransformed(IHqlExpression * expr)
  707. {
  708. //Can't short-circuit transformation if (!containsAlias(expr)) because it means references to transformed datasets won't get patched up
  709. IHqlExpression * body = expr->queryBody(true);
  710. if (body != expr)
  711. {
  712. OwnedHqlExpr ret = transform(body);
  713. return expr->cloneAnnotation(ret);
  714. }
  715. //slight difference from before...
  716. IHqlExpression * transformed = NewHqlTransformer::createTransformed(expr);
  717. CseScopeInfo * splitter = queryExtra(expr);
  718. if (splitter->aliasesToDefine.ordinality())
  719. {
  720. HqlExprArray args;
  721. args.append(*transformed);
  722. ForEachItemIn(idx, splitter->aliasesToDefine)
  723. {
  724. IHqlExpression * value = &splitter->aliasesToDefine.item(idx);
  725. args.append(*transform(value));
  726. }
  727. if (expr->isDataset())
  728. transformed = createDataset(no_alias_scope, args);
  729. else if (expr->isDatarow())
  730. transformed = createRow(no_alias_scope, args);
  731. else
  732. transformed = createValue(no_alias_scope, transformed->getType(), args);
  733. }
  734. return transformed;
  735. }
  736. ANewTransformInfo * CseScopeTransformer::createTransformInfo(IHqlExpression * expr)
  737. {
  738. return CREATE_NEWTRANSFORMINFO(CseScopeInfo, expr);
  739. }
  740. //First find the highest shared parent node (or this if no parents are shared)
  741. CseScopeInfo * CseScopeTransformer::calcCommonLocation(CseScopeInfo * extra)
  742. {
  743. if (extra->calcedCommonLocation)
  744. return extra->commonLocation;
  745. CseScopeInfo * commonLocation = extra;
  746. if (extra->firstParent)
  747. {
  748. CseScopeInfo * firstParentExtra = queryExtra(extra->firstParent);
  749. CseScopeInfo * commonParent = calcCommonLocation(firstParentExtra);
  750. if ((extra->parents.ordinality() == 0) && (!firstParentExtra->hasSharedParent || extra->firstParent->getOperator() == no_alias))
  751. // if ((extra->parents.ordinality() == 0) && !firstParentExtra->hasSharedParent)
  752. {
  753. //assertex(commonParent == firstParentExtra);
  754. //commonParent = extra;
  755. }
  756. else
  757. {
  758. extra->hasSharedParent = true;
  759. commonLocation = commonParent;
  760. ForEachItemIn(i, extra->parents)
  761. {
  762. CseScopeInfo * nextExtra = calcCommonLocation(queryExtra(extra->parents.item(i)));
  763. if (nextExtra->isUnconditional)
  764. extra->isUnconditional = true;
  765. commonLocation = findCommonPath(commonLocation, nextExtra);
  766. if (!commonLocation && extra->isUnconditional)
  767. break;
  768. }
  769. }
  770. }
  771. else
  772. {
  773. if (extra->hasSharedParent)
  774. commonLocation = NULL;
  775. }
  776. extra->calcedCommonLocation = true;
  777. extra->commonLocation = commonLocation;
  778. return commonLocation;
  779. }
  780. IHqlExpression * CseScopeTransformer::findAliasLocation(CseScopeInfo * extra)
  781. {
  782. CseScopeInfo * best = calcCommonLocation(extra);
  783. loop
  784. {
  785. if (!best)
  786. return NULL;
  787. IHqlExpression * bestLocation = best->original;
  788. if (canInsertCodeAlias(bestLocation))
  789. return bestLocation;
  790. best = selectParent(best);
  791. }
  792. }
  793. CseScopeInfo * CseScopeTransformer::selectParent(CseScopeInfo * info)
  794. {
  795. if (info->hasSharedParent)
  796. return info->commonLocation;
  797. if (!info->firstParent)
  798. return NULL;
  799. return queryExtra(info->firstParent);
  800. }
  801. CseScopeInfo * CseScopeTransformer::findCommonPath(CseScopeInfo * left, CseScopeInfo * right)
  802. {
  803. loop
  804. {
  805. if (!left || !right)
  806. return NULL;
  807. if (left == right)
  808. return left;
  809. if (left->seq > right->seq)
  810. left = selectParent(left);
  811. else
  812. right = selectParent(right);
  813. }
  814. }
  815. #else
  816. CSEentry::CSEentry(IHqlExpression * _value, PathArray & _path)
  817. {
  818. value.set(_value);
  819. unsigned depth=_path.ordinality();
  820. path.ensure(depth);
  821. ForEachItemIn(idx, _path)
  822. path.append(_path.item(idx));
  823. ensurePathValid();
  824. }
  825. void CSEentry::ensurePathValid()
  826. {
  827. //It is not valid to insert a no_code_alias at certain points....
  828. while (path.ordinality())
  829. {
  830. switch (path.tos().getOperator())
  831. {
  832. case no_range:
  833. case no_rangefrom:
  834. case no_rangeto:
  835. case no_rangecommon:
  836. case no_mapto:
  837. case no_recordlist:
  838. case no_transformlist:
  839. case no_rowvalue:
  840. case no_sortlist:
  841. path.pop();
  842. break;
  843. default:
  844. return;
  845. }
  846. }
  847. }
  848. void CSEentry::findCommonPath(PathArray & otherPath)
  849. {
  850. unsigned prevPath = path.ordinality();
  851. unsigned maxPath = path.ordinality();
  852. if (maxPath > otherPath.ordinality())
  853. maxPath = otherPath.ordinality();
  854. unsigned idx;
  855. for (idx = 0; idx < maxPath; idx++)
  856. {
  857. IHqlExpression * l = &path.item(idx);
  858. IHqlExpression * r = &otherPath.item(idx);
  859. if (l != r)
  860. break;
  861. }
  862. //Ensure the new location is valid for receiving the CSE
  863. while (idx != 0)
  864. {
  865. if (canWrapWithCSE(&path.item(idx-1)))
  866. break;
  867. idx--;
  868. }
  869. path.trunc(idx);
  870. if (prevPath != path.ordinality())
  871. {
  872. ForEachItemIn(idx2, dependsOn)
  873. dependsOn.item(idx2).findCommonPath(path);
  874. }
  875. ensurePathValid();
  876. }
  877. static HqlTransformerInfo cseScopeTransformerInfo("CseScopeTransformer");
  878. CseScopeTransformer::CseScopeTransformer()
  879. : NewHqlTransformer(cseScopeTransformerInfo)
  880. {
  881. }
  882. void CseScopeTransformer::analyseExpr(IHqlExpression * expr)
  883. {
  884. expr = expr->queryBody();
  885. if (!containsNonGlobalAlias(expr))
  886. return;
  887. CSEentry * cse = NULL;
  888. node_operator op = expr->getOperator();
  889. if (op == no_alias)
  890. {
  891. assertex(!expr->hasProperty(globalAtom));
  892. CseScopeInfo * splitter = queryExtra(expr);
  893. //PrintLog("splitter: %s", expr->toString(StringBuffer()).str());
  894. if (splitter->cseUse)
  895. {
  896. //Find the common path, and map the alias.
  897. CSEentry * cse = splitter->cseUse;
  898. cse->findCommonPath(path);
  899. if (activeCSE.ordinality())
  900. activeCSE.tos().dependsOn.append(*LINK(cse));
  901. return;
  902. }
  903. cse = new CSEentry(expr, path);
  904. splitter->cseUse.setown(cse);
  905. if (activeCSE.ordinality())
  906. activeCSE.tos().dependsOn.append(*LINK(cse));
  907. activeCSE.append(*LINK(cse));
  908. }
  909. #if 0
  910. if ((op == no_transform) || (op == no_newtransform))
  911. {
  912. //For a transform add each assignment as a path point - so the aliases for assignments don't end up
  913. //before aliases for skip attributes.
  914. path.append(*expr);
  915. ForEachChild(i, expr)
  916. {
  917. IHqlExpression * cur = expr->queryChild(i);
  918. analyseExpr(cur);
  919. path.append(*cur);
  920. }
  921. ForEachChild(i2, expr)
  922. path.pop();
  923. path.pop();
  924. }
  925. else
  926. #endif
  927. {
  928. path.append(*expr);
  929. NewHqlTransformer::analyseExpr(expr);
  930. path.pop();
  931. }
  932. //Add here so the cse are in the correct order to cope with dependencies...
  933. if (cse)
  934. {
  935. allCSEs.append(*LINK(cse));
  936. activeCSE.pop();
  937. }
  938. }
  939. bool CseScopeTransformer::attachCSEs(IHqlExpression * /*root*/)
  940. {
  941. bool changed = false;
  942. ForEachItemIn(idx, allCSEs)
  943. {
  944. CSEentry & cur = allCSEs.item(idx);
  945. if (cur.path.ordinality())
  946. {
  947. IHqlExpression & location = cur.path.tos();
  948. queryExtra(&location)->cseDefine.append(OLINK(cur));
  949. changed = true;
  950. }
  951. }
  952. return changed;
  953. }
  954. IHqlExpression * CseScopeTransformer::createTransformed(IHqlExpression * expr)
  955. {
  956. //Can't short-circuit transformation if (!containsAlias(expr)) because it means references to transformed datasets won't get patched up
  957. IHqlExpression * body = expr->queryBody(true);
  958. if (body != expr)
  959. {
  960. OwnedHqlExpr ret = transform(body);
  961. return expr->cloneAnnotation(ret);
  962. }
  963. //slight difference from before...
  964. IHqlExpression * transformed = NewHqlTransformer::createTransformed(expr);
  965. CseScopeInfo * splitter = queryExtra(expr);
  966. if (splitter->cseDefine.ordinality())
  967. {
  968. HqlExprArray args;
  969. args.append(*transformed);
  970. ForEachItemIn(idx, splitter->cseDefine)
  971. {
  972. CSEentry & cur = splitter->cseDefine.item(idx);
  973. args.append(*transform(cur.value));
  974. }
  975. if (expr->isDataset())
  976. transformed = createDataset(no_alias_scope, args);
  977. else if (expr->isDatarow())
  978. transformed = createRow(no_alias_scope, args);
  979. else
  980. transformed = createValue(no_alias_scope, transformed->getType(), args);
  981. }
  982. return transformed;
  983. }
  984. ANewTransformInfo * CseScopeTransformer::createTransformInfo(IHqlExpression * expr)
  985. {
  986. return CREATE_NEWTRANSFORMINFO(CseScopeInfo, expr);
  987. }
  988. #endif
  989. IHqlExpression * spotScalarCSE(IHqlExpression * expr, IHqlExpression * limit)
  990. {
  991. if (expr->isConstant())
  992. return LINK(expr);
  993. switch (expr->getOperator())
  994. {
  995. case no_select:
  996. if (!isNewSelector(expr))
  997. return LINK(expr);
  998. break;
  999. }
  1000. OwnedHqlExpr transformed = LINK(expr); //removeNamedSymbols(expr);
  1001. bool addedAliases = false;
  1002. //First spot the aliases - so that restructuring the ands doesn't lose any existing aliases.
  1003. {
  1004. CseSpotter spotter;
  1005. spotter.analyse(transformed, 0);
  1006. if (spotter.foundCandidates())
  1007. {
  1008. if (limit)
  1009. spotter.stopTransformation(limit);
  1010. transformed.setown(spotter.transformRoot(transformed));
  1011. addedAliases = spotter.createdNewAliases();
  1012. }
  1013. }
  1014. if (!containsAlias(transformed))
  1015. return transformed.getClear();
  1016. //Transform conjunctions so they are (a AND (b AND (c AND d))) not (((a AND b) AND c) AND d)
  1017. //so that alias scope can be introduced in a better place.
  1018. {
  1019. ConjunctionTransformer tr;
  1020. transformed.setown(tr.transformRoot(transformed));
  1021. }
  1022. if (!addedAliases)
  1023. return transformed.getClear();
  1024. //Now work out where in the tree the aliases should be evaluated.
  1025. {
  1026. CseScopeTransformer scoper;
  1027. scoper.analyse(transformed, 0);
  1028. if (scoper.attachCSEs(transformed))
  1029. transformed.setown(scoper.transformRoot(transformed));
  1030. }
  1031. return transformed.getClear();
  1032. }
  1033. void spotScalarCSE(SharedHqlExpr & expr, SharedHqlExpr & associated, IHqlExpression * limit, IHqlExpression * invariantSelector)
  1034. {
  1035. CseSpotter spotter;
  1036. spotter.analyse(expr, 0);
  1037. if (associated)
  1038. spotter.analyseAssociated(associated, 0);
  1039. if (!spotter.foundCandidates())
  1040. return;
  1041. if (limit)
  1042. spotter.stopTransformation(limit);
  1043. if (invariantSelector)
  1044. spotter.setInvariantSelector(invariantSelector);
  1045. expr.setown(spotter.transformRoot(expr));
  1046. associated.setown(spotter.transformRoot(associated));
  1047. }
  1048. void spotScalarCSE(HqlExprArray & exprs, HqlExprArray & associated, IHqlExpression * limit, IHqlExpression * invariantSelector)
  1049. {
  1050. CseSpotter spotter;
  1051. spotter.analyseArray(exprs, 0);
  1052. ForEachItemIn(ia, associated)
  1053. spotter.analyseAssociated(&associated.item(ia), 0);
  1054. if (!spotter.foundCandidates())
  1055. return;
  1056. if (limit)
  1057. spotter.stopTransformation(limit);
  1058. if (invariantSelector)
  1059. spotter.setInvariantSelector(invariantSelector);
  1060. HqlExprArray newExprs;
  1061. HqlExprArray newAssociated;
  1062. spotter.transformRoot(exprs, newExprs);
  1063. spotter.transformRoot(associated, newAssociated);
  1064. replaceArray(exprs, newExprs);
  1065. replaceArray(associated, newAssociated);
  1066. }
  1067. //---------------------------------------------------------------------------
  1068. //The TableInvariantTransformer is important for ensuring that getResultXXX code is executed in the code context, amongst other things
  1069. //It must ensure that any global aliases couldn't contain some other global aliases inside a child query, otherwise when the child query is
  1070. //evaluated the result won't be in the correct place.
  1071. //
  1072. //MORE: This could be improved to work out whether it is worth creating an alias (which will then be serialized...)
  1073. //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
  1074. //however it is pretty good as it stands.
  1075. //ideally it would need information about how many times the expression is likely to be evaluated (e.g., 1/many)
  1076. //so that could be taken into account (e.g, filenames which are 'string' + conditional)
  1077. static bool canHoistInvariant(IHqlExpression * expr)
  1078. {
  1079. if (!canCreateTemporary(expr))
  1080. {
  1081. if ((expr->getOperator() != no_alias) || expr->hasProperty(globalAtom))
  1082. return false;
  1083. }
  1084. if (!expr->isPure())
  1085. return false;
  1086. switch (expr->getOperator())
  1087. {
  1088. case no_list:
  1089. case no_datasetlist:
  1090. return false; // probably don't want to hoist these
  1091. }
  1092. return true;
  1093. }
  1094. static HqlTransformerInfo tableInvariantTransformerInfo("TableInvariantTransformer");
  1095. TableInvariantTransformer::TableInvariantTransformer() : NewHqlTransformer(tableInvariantTransformerInfo)
  1096. {
  1097. canAlias = true;
  1098. }
  1099. bool TableInvariantTransformer::isInvariant(IHqlExpression * expr)
  1100. {
  1101. TableInvariantInfo * extra = queryBodyExtra(expr);
  1102. if (extra->cachedInvariant)
  1103. return extra->isInvariant;
  1104. bool invariant = false;
  1105. node_operator op = expr->getOperator();
  1106. switch (op)
  1107. {
  1108. case no_record:
  1109. case no_null:
  1110. case no_activetable:
  1111. case no_activerow:
  1112. case no_left:
  1113. case no_right:
  1114. case no_self:
  1115. case no_top:
  1116. case no_selfref:
  1117. case no_filepos:
  1118. case no_file_logicalname:
  1119. case no_joined:
  1120. case no_offsetof:
  1121. case no_sizeof:
  1122. case NO_AGGREGATE:
  1123. break;
  1124. case no_preservemeta:
  1125. invariant = isInvariant(expr->queryChild(0));
  1126. break;
  1127. case no_constant:
  1128. case no_workunit_dataset:
  1129. case no_getresult:
  1130. case no_getgraphresult:
  1131. invariant = true;
  1132. break;
  1133. case no_select:
  1134. {
  1135. if (!expr->isDataset())
  1136. {
  1137. IHqlExpression * ds = expr->queryChild(0);
  1138. if (expr->hasProperty(newAtom) || ds->isDatarow())
  1139. invariant = isInvariant(ds);
  1140. }
  1141. break;
  1142. }
  1143. case no_newaggregate:
  1144. {
  1145. //Allow these on a very strict subset of the datasets - to ensure that no potential globals can be included in the dataset
  1146. if (!isInvariant(expr->queryChild(0)))
  1147. break;
  1148. switch (querySimpleAggregate(expr, false, true))
  1149. {
  1150. case no_existsgroup:
  1151. case no_countgroup:
  1152. invariant = true;
  1153. break;
  1154. }
  1155. break;
  1156. }
  1157. case no_selectnth:
  1158. switch (expr->queryChild(1)->getOperator())
  1159. {
  1160. case no_constant:
  1161. case no_counter:
  1162. invariant = isInvariant(expr->queryChild(0));
  1163. break;
  1164. }
  1165. break;
  1166. default:
  1167. if (!isContextDependent(expr))
  1168. {
  1169. if (!expr->isAction())// && !expr->isDataset() && !expr->isDatarow())
  1170. {
  1171. invariant = true;
  1172. ForEachChild(i, expr)
  1173. {
  1174. IHqlExpression * cur = expr->queryChild(i);
  1175. if (!isInvariant(cur))
  1176. {
  1177. invariant = false;
  1178. break;
  1179. }
  1180. }
  1181. }
  1182. }
  1183. break;
  1184. }
  1185. extra->cachedInvariant = true;
  1186. extra->isInvariant = invariant;
  1187. return invariant;
  1188. }
  1189. #if 0
  1190. void TableInvariantTransformer::analyseExpr(IHqlExpression * expr)
  1191. {
  1192. expr = expr->queryBody();
  1193. if (alreadyVisited(expr))
  1194. return;
  1195. node_operator op = expr->getOperator();
  1196. switch (op)
  1197. {
  1198. case no_record:
  1199. case no_constant:
  1200. return;
  1201. }
  1202. if (isInvariant(expr) && !expr->isAttribute() && !expr->isConstant() && canHoistInvariant(expr))
  1203. {
  1204. TableInvariantInfo * extra = queryBodyExtra(expr);
  1205. if (op == no_alias)
  1206. {
  1207. if (!expr->hasProperty(globalAtom))
  1208. extra->createAlias = true;
  1209. }
  1210. else
  1211. extra->createAlias = true;
  1212. return;
  1213. }
  1214. if (op == no_attr_expr)
  1215. analyseChildren(expr);
  1216. else
  1217. NewHqlTransformer::analyseExpr(expr);
  1218. }
  1219. #else
  1220. void TableInvariantTransformer::analyseExpr(IHqlExpression * expr)
  1221. {
  1222. expr = expr->queryBody();
  1223. TableInvariantInfo * extra = queryBodyExtra(expr);
  1224. if (alreadyVisited(expr))
  1225. return;
  1226. //More - these need to be handled properly...
  1227. node_operator op = expr->getOperator();
  1228. switch (op)
  1229. {
  1230. case no_record:
  1231. case no_constant:
  1232. return;
  1233. }
  1234. //We are trying to ensure that any expressions that don't access fields that are dependent on the activeDatasets/context are only
  1235. //evaluated once => check for active dataset rather than any dataset
  1236. bool candidate = false;
  1237. if (!isContextDependent(expr) && !expr->isAttribute())
  1238. {
  1239. if (isInlineTrivialDataset(expr) && !expr->isConstant())
  1240. {
  1241. candidate = (op != no_null);
  1242. }
  1243. else
  1244. {
  1245. if (!containsActiveDataset(expr))
  1246. {
  1247. //MORE: We should be able to hoist constant datasets (e.g., temptables), but it causes problems
  1248. //e.g., stops items it contains from being aliased. So
  1249. if (!expr->isAction() && !expr->isDataset() && !expr->isDatarow())
  1250. {
  1251. switch (op)
  1252. {
  1253. case no_alias:
  1254. if (!expr->hasProperty(globalAtom))
  1255. extra->createAlias = true;
  1256. return;
  1257. default:
  1258. //MORE: We should be able to hoist constant datasets (e.g., temptables), but it causes problems
  1259. //e.g., stops items it contains from being aliased.
  1260. candidate = !expr->isConstant();
  1261. break;
  1262. }
  1263. }
  1264. }
  1265. }
  1266. if (candidate && canHoistInvariant(expr))
  1267. {
  1268. extra->createAlias = true;
  1269. return;
  1270. }
  1271. }
  1272. if (op == no_attr_expr)
  1273. analyseChildren(expr);
  1274. else
  1275. NewHqlTransformer::analyseExpr(expr);
  1276. }
  1277. #endif
  1278. bool TableInvariantTransformer::isAlwaysAlias(IHqlExpression * expr)
  1279. {
  1280. if (queryBodyExtra(expr)->createAlias)
  1281. return true;
  1282. switch (expr->getOperator())
  1283. {
  1284. case no_alias:
  1285. case no_getresult: // these are commoned up in the code generator, so don't do it twice.
  1286. case no_getgraphresult:
  1287. case no_getgraphloopresult:
  1288. return true;
  1289. }
  1290. return false;
  1291. }
  1292. bool TableInvariantTransformer::isTrivialAlias(IHqlExpression * expr)
  1293. {
  1294. switch (expr->getOperator())
  1295. {
  1296. case no_cast:
  1297. case no_implicitcast:
  1298. //Don't create aliases for items that are simply integral casts of other aliases.
  1299. {
  1300. ITypeInfo * type = expr->queryType();
  1301. if (type->isInteger())
  1302. {
  1303. IHqlExpression * cast = expr->queryChild(0);
  1304. ITypeInfo * castType = cast->queryType();
  1305. if (castType->isInteger() && isAlwaysAlias(cast))
  1306. {
  1307. switch (type->getSize())
  1308. {
  1309. case 1: case 2: case 4: case 8:
  1310. return true;
  1311. }
  1312. }
  1313. }
  1314. break;
  1315. }
  1316. case no_not:
  1317. {
  1318. IHqlExpression * child = expr->queryChild(0);
  1319. if (isAlwaysAlias(child))
  1320. return true;
  1321. break;
  1322. }
  1323. }
  1324. return false;
  1325. }
  1326. IHqlExpression * TableInvariantTransformer::createTransformed(IHqlExpression * expr)
  1327. {
  1328. if (expr->getOperator() == no_alias)
  1329. {
  1330. OwnedHqlExpr newChild = transform(expr->queryChild(0));
  1331. if (newChild->getOperator() == no_alias)
  1332. return newChild.getClear();
  1333. }
  1334. OwnedHqlExpr transformed = NewHqlTransformer::createTransformed(expr);
  1335. if (queryBodyExtra(expr)->createAlias)
  1336. {
  1337. if (!isTrivialAlias(expr))
  1338. {
  1339. OwnedHqlExpr attr = createAttribute(globalAtom);
  1340. if (transformed->getOperator() == no_alias)
  1341. transformed.set(transformed->queryChild(0));
  1342. return createAlias(transformed->queryBody(), attr);
  1343. }
  1344. }
  1345. return transformed.getClear();
  1346. }
  1347. //---------------------------------------------------------------------------
  1348. IHqlExpression * spotTableInvariant(IHqlExpression * expr)
  1349. {
  1350. TableInvariantTransformer transformer;
  1351. transformer.analyse(expr, 0);
  1352. return transformer.transformRoot(expr);
  1353. }
  1354. IHqlExpression * spotTableInvariantChildren(IHqlExpression * expr)
  1355. {
  1356. TableInvariantTransformer transformer;
  1357. ForEachChild(i1, expr)
  1358. transformer.analyse(expr->queryChild(i1), 0);
  1359. return transformer.transformRoot(expr);
  1360. }
  1361. //---------------------------------------------------------------------------
  1362. static HqlTransformerInfo globalAliasTransformerInfo("GlobalAliasTransformer");
  1363. GlobalAliasTransformer::GlobalAliasTransformer() : NewHqlTransformer(globalAliasTransformerInfo)
  1364. {
  1365. insideGlobal = false;
  1366. }
  1367. void GlobalAliasTransformer::analyseExpr(IHqlExpression * expr)
  1368. {
  1369. if (!containsAlias(expr))
  1370. return;
  1371. bool wasInsideGlobal = insideGlobal;
  1372. GlobalAliasInfo * extra = queryBodyExtra(expr);
  1373. extra->numUses++;
  1374. if (expr->getOperator() == no_alias)
  1375. {
  1376. if (expr->hasProperty(globalAtom))
  1377. {
  1378. // assertex(!containsActiveDataset(expr) || isInlineTrivialDataset(expr));
  1379. if (!insideGlobal)
  1380. extra->isOuter = true;
  1381. }
  1382. if (extra->numUses > 1)
  1383. return;
  1384. if (extra->isOuter)
  1385. insideGlobal = true;
  1386. }
  1387. else
  1388. {
  1389. //ugly, but we need to walk children more than once even if we've already been here.
  1390. //What is important is if visited >1 or occur globally, so can short circuit based on that condition.
  1391. //This currently links too many times because subsequent cse generation may common up multiple uses of the same item
  1392. //but it's not too bad.
  1393. //We could rerun this again if that was a major issue.
  1394. if (insideGlobal)
  1395. {
  1396. if (extra->numUses > 2)
  1397. return; // may need to visit children more than once so that alias is linked twice.
  1398. }
  1399. else
  1400. {
  1401. if (extra->isOuter && (extra->numUses > 2))
  1402. return;
  1403. extra->isOuter = true;
  1404. }
  1405. }
  1406. if (expr->getOperator() == no_attr_expr)
  1407. analyseChildren(expr);
  1408. else
  1409. NewHqlTransformer::analyseExpr(expr);
  1410. insideGlobal = wasInsideGlobal;
  1411. }
  1412. IHqlExpression * GlobalAliasTransformer::createTransformed(IHqlExpression * expr)
  1413. {
  1414. OwnedHqlExpr transformed = NewHqlTransformer::createTransformed(expr);
  1415. if ((expr->getOperator() == no_alias))
  1416. {
  1417. GlobalAliasInfo * extra = queryBodyExtra(expr);
  1418. if (expr->hasProperty(globalAtom))
  1419. {
  1420. if (!extra->isOuter)
  1421. {
  1422. if (extra->numUses == 1)
  1423. return LINK(transformed->queryChild(0));
  1424. if (!expr->hasProperty(localAtom))
  1425. return appendLocalAttribute(transformed);
  1426. }
  1427. else if (expr->hasProperty(localAtom))
  1428. {
  1429. //Should never occur - but just about conceivable that some kind of constant folding
  1430. //might cause a surrounding global alias to be removed.
  1431. return removeLocalAttribute(transformed);
  1432. }
  1433. }
  1434. else
  1435. {
  1436. if ((extra->numUses == 1) && !expr->hasProperty(internalAtom))
  1437. return LINK(transformed->queryChild(0));
  1438. }
  1439. }
  1440. return transformed.getClear();
  1441. }
  1442. //---------------------------------------------------------------------------
  1443. IHqlExpression * optimizeActivityAliasReferences(IHqlExpression * expr)
  1444. {
  1445. if (!containsAlias(expr))
  1446. return LINK(expr);
  1447. unsigned first = getFirstActivityArgument(expr);
  1448. unsigned last = first + getNumActivityArguments(expr);
  1449. bool foundAlias = false;
  1450. ForEachChild(i1, expr)
  1451. {
  1452. IHqlExpression * cur = expr->queryChild(i1);
  1453. if (((i1 < first) || (i1 >= last)) && containsAlias(cur))
  1454. {
  1455. foundAlias = true;
  1456. break;
  1457. }
  1458. }
  1459. if (!foundAlias)
  1460. return LINK(expr);
  1461. GlobalAliasTransformer transformer;
  1462. ForEachChild(i2, expr)
  1463. {
  1464. IHqlExpression * cur = expr->queryChild(i2);
  1465. if (((i2 < first) || (i2 >= last)) && containsAlias(cur))
  1466. transformer.analyse(cur, 0);
  1467. }
  1468. HqlExprArray args;
  1469. ForEachChild(i3, expr)
  1470. {
  1471. IHqlExpression * cur = expr->queryChild(i3);
  1472. if ((i3 < first) || (i3 >= last))
  1473. args.append(*transformer.transformRoot(cur));
  1474. else
  1475. args.append(*LINK(cur));
  1476. }
  1477. return cloneOrLink(expr, args);
  1478. }