hqlcppcase.cpp 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140
  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 "jliball.hpp"
  15. #include "hql.hpp"
  16. #include "platform.h"
  17. #include "jlib.hpp"
  18. #include "jexcept.hpp"
  19. #include "jmisc.hpp"
  20. #include "hql.hpp"
  21. #include "hqlfunc.hpp"
  22. #include "hqlcpp.ipp"
  23. #include "hqlwcpp.hpp"
  24. #include "hqlutil.hpp"
  25. #include "hqlcpputil.hpp"
  26. #include "hqlcatom.hpp"
  27. #include "hqlcerrors.hpp"
  28. #define INTEGER_SEARCH_THRESHOLD 30 // above this, a table search is generated.
  29. #define MAX_NUM_NOBREAK_CASE 80 // maximum number of case: without a break - compiler workaround
  30. #define INLINE_COMPARE_THRESHOLD 2 // above this, a loop is generated
  31. #define SWITCH_TABLE_DENSITY_THRESHOLD 3 // % used before use array index.
  32. #define MAX_NESTED_CASES 8 // to stop C++ compiler running out of scopes.
  33. //===========================================================================
  34. static _ATOM searchDataTableAtom;
  35. static _ATOM searchEStringTableAtom;
  36. static _ATOM searchQStringTableAtom;
  37. static _ATOM searchStringTableAtom;
  38. static _ATOM searchVStringTableAtom;
  39. //===========================================================================
  40. MODULE_INIT(INIT_PRIORITY_STANDARD)
  41. {
  42. searchDataTableAtom = createIdentifierAtom("searchDataTable");
  43. searchEStringTableAtom = createIdentifierAtom("searchEStringTable");
  44. searchQStringTableAtom = createIdentifierAtom("searchQStringTable");
  45. searchStringTableAtom = createIdentifierAtom("searchStringTable");
  46. searchVStringTableAtom = createIdentifierAtom("searchVStringTable");
  47. return true;
  48. }
  49. MODULE_EXIT()
  50. {
  51. }
  52. //===========================================================================
  53. //Case helper functions...
  54. void cvtChooseListToPairs(HqlExprArray & target, IHqlExpression * from, unsigned base)
  55. {
  56. unsigned max = from->numChildren();
  57. unsigned idx;
  58. target.ensure(max);
  59. for (idx = 0; idx < max; idx++)
  60. {
  61. IHqlExpression * v1 = createConstant(createIntValue(idx+base, LINK(unsignedType)));
  62. IHqlExpression * v2 = from->queryChild(idx);
  63. ITypeInfo * type = v2->queryType();
  64. target.append(* createValue(no_mapto, LINK(type), v1, LINK(v2)));
  65. }
  66. }
  67. void cvtIndexListToPairs(HqlExprArray & target, IHqlExpression * from)
  68. {
  69. unsigned max = from->numChildren();
  70. unsigned idx;
  71. target.ensure(max);
  72. for (idx = 0; idx < max; idx++)
  73. {
  74. IHqlExpression * v1 = from->queryChild(idx);
  75. IHqlExpression * v2 = createConstant(createIntValue(idx+1, LINK(unsignedType)));
  76. ITypeInfo * type = v2->queryType();
  77. target.append(* createValue(no_mapto, LINK(type), LINK(v1), v2));
  78. }
  79. }
  80. void cvtInListToPairs(HqlExprArray & target, IHqlExpression * from, bool valueIfMatch)
  81. {
  82. unsigned max = from->numChildren();
  83. unsigned idx;
  84. IHqlExpression * tValue = queryBoolExpr(valueIfMatch);
  85. ITypeInfo * type = queryBoolType();
  86. target.ensure(max);
  87. for (idx = 0; idx < max; idx++)
  88. {
  89. IHqlExpression * v1 = from->queryChild(idx);
  90. target.append(* createValue(no_mapto, LINK(type), LINK(v1), LINK(tValue)));
  91. }
  92. }
  93. IHqlExpression * createNotFoundValue()
  94. {
  95. OwnedITypeInfo int4 = makeIntType(4, true);
  96. return createConstant(int4->castFrom(true, -1));
  97. }
  98. //===========================================================================
  99. static int comparePair(IInterface * * left, IInterface * * right)
  100. {
  101. IHqlExpression * lexpr = (IHqlExpression *)*left;
  102. IHqlExpression * rexpr = (IHqlExpression *)*right;
  103. return lexpr->queryChild(0)->queryValue()->compare(rexpr->queryChild(0)->queryValue());
  104. }
  105. HqlCppCaseInfo::HqlCppCaseInfo(HqlCppTranslator & _translator) : translator(_translator)
  106. {
  107. complexCompare = false;
  108. constantCases = true;
  109. constantValues = true;
  110. indexType.setown(makeIntType(sizeof(int), true));
  111. }
  112. void HqlCppCaseInfo::addPair(IHqlExpression * expr)
  113. {
  114. pairs.append(*LINK(expr));
  115. IHqlExpression * compareValue = expr->queryChild(0);
  116. if (!compareValue->queryValue())
  117. constantCases = false;
  118. if (!expr->queryChild(1)->queryValue())
  119. constantValues = false;
  120. if (cond && !complexCompare)
  121. {
  122. ITypeInfo * valueType = compareValue->queryType();
  123. if (valueType != cond->queryType())
  124. complexCompare = isCompare3Valued(compareValue->queryType());
  125. }
  126. updateResultType(expr->queryChild(1));
  127. }
  128. void HqlCppCaseInfo::addPairs(HqlExprArray & _pairs)
  129. {
  130. pairs.ensure(_pairs.ordinality());
  131. ForEachItemIn(idx, _pairs)
  132. addPair(&_pairs.item(idx));
  133. }
  134. bool HqlCppCaseInfo::buildAssign(BuildCtx & ctx, const CHqlBoundTarget & target)
  135. {
  136. if (pairs.ordinality() == 0)
  137. {
  138. translator.buildExprAssign(ctx, target, defaultValue);
  139. }
  140. else if (cond.get() && constantCases)
  141. {
  142. processBranches();
  143. BuildCtx subctx(ctx);
  144. CHqlBoundExpr test;
  145. buildSwitchCondition(ctx, test);
  146. if (complexCompare)
  147. {
  148. if ((pairs.ordinality() > INLINE_COMPARE_THRESHOLD) || (translator.getHints() & HintSize))
  149. {
  150. if (okToAlwaysEvaluateDefault() || hasLibraryChop())
  151. buildLoopChopMap(subctx, target, test);
  152. else
  153. buildGeneralAssign(subctx, target);
  154. }
  155. else
  156. {
  157. if (okToAlwaysEvaluateDefault())
  158. buildChop3Map(subctx, target, test);
  159. else
  160. buildGeneralAssign(subctx, target);
  161. }
  162. }
  163. else
  164. {
  165. ITypeInfo * condType = test.queryType()->queryPromotedType();
  166. if (!queryBuildArrayLookup(subctx, target, test))
  167. {
  168. if (condType->getTypeCode() != type_real)
  169. {
  170. OwnedHqlExpr search = test.getTranslatedExpr();
  171. if (constantValues && (condType->getTypeCode() == type_int) && (pairs.ordinality() > INTEGER_SEARCH_THRESHOLD) && canBuildStaticList(resultType))
  172. buildIntegerSearchMap(subctx, target, search);
  173. else
  174. buildSwitchMap(subctx, &target, test.expr);
  175. }
  176. else
  177. {
  178. if (okToAlwaysEvaluateDefault() && pairs.ordinality() > 4)
  179. {
  180. translator.buildExprAssign(ctx, target, defaultValue);
  181. buildChop2Map(subctx, target, test, 0, pairs.ordinality());
  182. }
  183. else
  184. buildGeneralAssign(subctx, target);
  185. }
  186. }
  187. }
  188. }
  189. else
  190. buildGeneralAssign(ctx, target);
  191. return true;
  192. }
  193. bool HqlCppCaseInfo::buildReturn(BuildCtx & ctx)
  194. {
  195. if (pairs.ordinality() == 0)
  196. {
  197. translator.buildReturn(ctx, defaultValue);
  198. }
  199. else if (cond.get() && constantCases)
  200. {
  201. processBranches();
  202. BuildCtx subctx(ctx);
  203. CHqlBoundExpr test;
  204. buildSwitchCondition(ctx, test);
  205. if (complexCompare)
  206. {
  207. buildGeneralReturn(subctx);
  208. }
  209. else
  210. {
  211. //if canBuildArrayLookup(test)
  212. //if use a lookup table to map value->constants
  213. if (test.queryType()->getTypeCode() != type_real)
  214. buildSwitchMap(subctx, NULL, test.expr);
  215. else
  216. buildGeneralReturn(subctx);
  217. }
  218. }
  219. else
  220. buildGeneralReturn(ctx);
  221. return true;
  222. }
  223. void HqlCppCaseInfo::buildChop3Map(BuildCtx & ctx, const CHqlBoundTarget & target, CHqlBoundExpr & test, IHqlExpression * temp, unsigned start, unsigned end)
  224. {
  225. if ((end - start) <= 2)
  226. buildChop2Map(ctx, target, test, start, end);
  227. else
  228. {
  229. unsigned mid = (start + end) / 2;
  230. generateCompareVar(ctx, temp, test, queryCompare(mid));
  231. OwnedHqlExpr test1 = createValue(no_eq, LINK(temp), getZero());
  232. OwnedHqlExpr test2 = createValue(no_lt, LINK(temp), getZero());
  233. BuildCtx subctx(ctx);
  234. IHqlStmt * if1 = subctx.addFilter(test1); // if (test == 0)
  235. translator.buildExprAssign(subctx, target, queryReturn(mid)); // target = value(n)
  236. subctx.selectElse(if1); // else
  237. IHqlStmt * if2 = subctx.addFilter(test2); // if (test < 0)
  238. buildChop3Map(subctx, target, test, temp, start, mid); // repeat for start..mid
  239. subctx.selectElse(if2); // else
  240. buildChop3Map(subctx, target, test, temp, mid+1, end); // repeat for min..end
  241. }
  242. }
  243. void HqlCppCaseInfo::buildChop3Map(BuildCtx & ctx, const CHqlBoundTarget & target, CHqlBoundExpr & test)
  244. {
  245. //need to hack it because there is no signed integer type
  246. OwnedHqlExpr tempVar = ctx.getTempDeclare(indexType, NULL);
  247. translator.buildExprAssign(ctx, target, defaultValue);
  248. buildChop3Map(ctx, target, test, tempVar, 0, getNumPairs());
  249. }
  250. void HqlCppCaseInfo::buildChop2Map(BuildCtx & ctx, const CHqlBoundTarget & target, CHqlBoundExpr & test, unsigned start, unsigned end)
  251. {
  252. BuildCtx subctx(ctx);
  253. if ((end - start) <= 3) // (1,2,3) avg(2) cf. (2,2,3) avg(2.3)
  254. {
  255. //optimize the case where they all create the same value
  256. bool same = true;
  257. unsigned index;
  258. for (index=start+1; index < end; ++index)
  259. {
  260. if (queryReturn(index-1) != queryReturn(index))
  261. {
  262. same = false;
  263. break;
  264. }
  265. }
  266. if (same)
  267. {
  268. CompoundBuilder cb(no_or);
  269. for (index=start; index < end; ++index)
  270. {
  271. IHqlExpression * compare = queryCompare(index);
  272. IHqlExpression * cond = createCompareExpr(no_eq, test.getTranslatedExpr(), LINK(compare));
  273. cb.addOperand(cond);
  274. }
  275. OwnedHqlExpr compound = cb.getCompound();
  276. translator.buildFilter(subctx, compound);
  277. translator.buildExprAssign(subctx, target, queryReturn(start));
  278. }
  279. else
  280. {
  281. IHqlStmt * stmt = NULL;
  282. for (index=start; index < end; ++index)
  283. {
  284. if (stmt)
  285. subctx.selectElse(stmt);
  286. IHqlExpression * compare = queryCompare(index);
  287. OwnedHqlExpr cond = createCompareExpr(no_eq, test.getTranslatedExpr(), LINK(compare));
  288. CHqlBoundExpr bound;
  289. translator.buildExpr(subctx, cond, bound);
  290. stmt = subctx.addFilter(bound.expr);
  291. translator.buildExprAssign(subctx, target, queryReturn(index));
  292. }
  293. }
  294. }
  295. else
  296. {
  297. unsigned mid = (start + end) / 2;
  298. IHqlExpression * compare = queryCompare(mid);
  299. OwnedHqlExpr cond = createCompareExpr(no_lt, test.getTranslatedExpr(), LINK(compare));
  300. CHqlBoundExpr bound;
  301. translator.buildExpr(subctx, cond, bound);
  302. IHqlStmt * stmt = subctx.addFilter(bound.expr);
  303. buildChop2Map(subctx, target, test, start, mid);
  304. subctx.selectElse(stmt);
  305. buildChop2Map(subctx, target, test, mid, end);
  306. }
  307. }
  308. IHqlExpression * HqlCppCaseInfo::buildIndexedMap(BuildCtx & ctx, IHqlExpression * test, unsigned lower, unsigned upper)
  309. {
  310. ITypeInfo * compareType = test->queryType()->queryPromotedType();
  311. type_t compareTypeCode = compareType->getTypeCode();
  312. HqlExprArray values;
  313. IHqlExpression * dft = queryActiveTableSelector(); // value doesn't matter as long as it will not occur
  314. unsigned num = (upper-lower+1);
  315. values.ensure(num);
  316. unsigned idx;
  317. for (idx = 0; idx < num; idx++)
  318. values.append(*LINK(dft));
  319. ForEachItemIn(idx2, pairs)
  320. {
  321. IHqlExpression & cur = pairs.item(idx2);
  322. IValue * value = cur.queryChild(0)->queryValue();
  323. unsigned replaceIndex;
  324. switch (compareTypeCode)
  325. {
  326. case type_int:
  327. replaceIndex = (int)value->getIntValue()-lower;
  328. break;
  329. case type_string:
  330. {
  331. StringBuffer temp;
  332. value->getStringValue(temp);
  333. replaceIndex = (int)(unsigned char)temp.charAt(0)-lower;
  334. break;
  335. }
  336. default:
  337. throwUnexpectedType(compareType);
  338. }
  339. IHqlExpression * mapTo = cur.queryChild(1);
  340. if (mapTo->getOperator() != no_constant)
  341. throwUnexpected();
  342. if (replaceIndex >= num)
  343. translator.reportWarning(HQLWRN_CaseCanNeverMatch, "CASE entry %d can never match the test condition", replaceIndex);
  344. else
  345. values.replace(*LINK(mapTo),replaceIndex);
  346. }
  347. //Now replace the placeholders with the default values.
  348. for (idx = 0; idx < num; idx++)
  349. {
  350. if (&values.item(idx) == dft)
  351. values.replace(*defaultValue.getLink(),idx);
  352. }
  353. // use a var string type to get better C++ generated...
  354. ITypeInfo * storeType = getArrayElementType(resultType);
  355. ITypeInfo * listType = makeArrayType(storeType, values.ordinality());
  356. OwnedHqlExpr lvalues = createValue(no_list, listType, values);
  357. CHqlBoundExpr boundTable;
  358. translator.buildExpr(ctx, lvalues, boundTable);
  359. IHqlExpression * tableIndex;
  360. switch (compareTypeCode)
  361. {
  362. case type_int:
  363. tableIndex = LINK(test);
  364. break;
  365. case type_string:
  366. tableIndex = createValue(no_index, makeCharType(), LINK(test), getZero());
  367. break;
  368. default:
  369. throwUnexpectedType(compareType);
  370. }
  371. ITypeInfo * retType = resultType;
  372. IHqlExpression * ret = createValue(no_index, LINK(retType), LINK(boundTable.expr), tableIndex);
  373. return createTranslatedOwned(ret);
  374. }
  375. void HqlCppCaseInfo::buildLoopChopMap(BuildCtx & ctx, const CHqlBoundTarget & target, CHqlBoundExpr & test)
  376. {
  377. //Declare a table that contains all the strings...
  378. ITypeInfo * compareType = queryCompareType();
  379. type_t ctc = compareType->getTypeCode();
  380. if ((ctc == type_data) && !hasLibraryChop())
  381. {
  382. buildGeneralAssign(ctx, target);
  383. return;
  384. }
  385. OwnedHqlExpr values = createCompareList();
  386. CHqlBoundExpr boundTable;
  387. translator.buildExpr(ctx, values, boundTable);
  388. OwnedHqlExpr midVar = createVariable(LINK(indexType));
  389. if (hasLibraryChop())
  390. {
  391. ITypeInfo * tableEntryType = makeReferenceModifier(LINK(compareType));
  392. ITypeInfo * tableType = makePointerType(tableEntryType);
  393. HqlExprArray args;
  394. _ATOM func;
  395. switch (ctc)
  396. {
  397. case type_data:
  398. func = searchDataTableAtom;
  399. break;
  400. case type_varstring:
  401. func = searchVStringTableAtom;
  402. break;
  403. case type_qstring:
  404. func = searchQStringTableAtom;
  405. break;
  406. case type_string:
  407. if (compareType->queryCharset()->queryName() == asciiAtom)
  408. func = searchStringTableAtom;
  409. else if (compareType->queryCharset()->queryName() == ebcdicAtom)
  410. func = searchEStringTableAtom;
  411. else
  412. UNIMPLEMENTED;
  413. break;
  414. case type_unicode:
  415. func = searchUnicodeTableAtom;
  416. break;
  417. case type_utf8:
  418. func = searchUtf8TableAtom;
  419. break;
  420. case type_varunicode:
  421. func = searchVUnicodeTableAtom;
  422. break;
  423. default:
  424. throwUnexpectedType(compareType);
  425. }
  426. args.append(*getSizetConstant(values->numChildren()));
  427. if ((ctc != type_varstring) && (ctc != type_varunicode))
  428. args.append(*getSizetConstant(values->queryChild(0)->queryType()->getStringLen()));
  429. args.append(*createValue(no_address, tableType, createValue(no_index, LINK(tableEntryType), LINK(boundTable.expr), getZero())));
  430. if ((ctc != type_varstring) && (ctc != type_varunicode))
  431. args.append(*translator.getBoundLength(test));
  432. args.append(*ensureIndexable(test.expr));
  433. if ((ctc==type_unicode) || (ctc == type_varunicode) || (ctc == type_utf8))
  434. args.append(*createConstant(compareType->queryLocale()->str()));
  435. OwnedHqlExpr call = translator.bindTranslatedFunctionCall(func, args);
  436. OwnedHqlExpr search = createTranslated(call);
  437. bool includeDefaultInResult = false;
  438. OwnedHqlExpr resultExpr = createResultsExpr(midVar, true, &includeDefaultInResult);
  439. OwnedHqlExpr simpleResult = queryCreateSimpleResultAssign(search, resultExpr);
  440. if (simpleResult)
  441. translator.buildExprAssign(ctx, target, simpleResult);
  442. else
  443. {
  444. ctx.addDeclare(midVar, NULL);
  445. translator.buildAssignToTemp(ctx, midVar, search);
  446. if (includeDefaultInResult)
  447. {
  448. translator.buildExprAssign(ctx, target, resultExpr);
  449. }
  450. else
  451. {
  452. OwnedHqlExpr compare = createBoolExpr(no_ne, LINK(midVar), createNotFoundValue());
  453. BuildCtx subctx(ctx);
  454. IHqlStmt * stmt = subctx.addFilter(compare);
  455. translator.buildExprAssign(subctx, target, resultExpr);
  456. subctx.selectElse(stmt);
  457. translator.buildExprAssign(subctx, target, defaultValue);
  458. }
  459. }
  460. }
  461. else
  462. {
  463. #if 0
  464. //Keep this as a reminder of what was needed to fix qstrings.
  465. if (ctc == type_qstring)
  466. {
  467. Linked<ITypeInfo> compareType = queryCompareType();
  468. compareType.setown(makeArrayType(compareType.getLink()));
  469. table = createValue(no_typetransfer, compareType.getLink(), table);
  470. }
  471. #endif
  472. OwnedHqlExpr resultExpr = createResultsExpr(midVar, false);
  473. //Now generate the code that performs the binary chop..
  474. ctx.addDeclare(midVar, NULL);
  475. OwnedHqlExpr compareVar = ctx.getTempDeclare(indexType, NULL);
  476. OwnedHqlExpr leftVar = ctx.getTempDeclare(indexType, NULL);
  477. OwnedHqlExpr rightVar = ctx.getTempDeclare(indexType, NULL);
  478. OwnedHqlExpr numPairs = getSizetConstant(getNumPairs());
  479. ctx.addAssign(leftVar, queryZero());
  480. ctx.addAssign(rightVar, numPairs);
  481. translator.buildExprAssign(ctx, target, defaultValue);
  482. OwnedHqlExpr loopc = createBoolExpr(no_lt, LINK(leftVar), LINK(rightVar));
  483. OwnedHqlExpr mid = createValue(no_div, createValue(no_add, LINK(leftVar), LINK(rightVar)), createConstant(indexType->castFrom(false, 2)));
  484. OwnedHqlExpr mid_p1 = createValue(no_add, LINK(indexType), LINK(midVar), createConstant(indexType->castFrom(false, 1)));
  485. OwnedHqlExpr curelem = createValue(no_index, LINK(compareType), boundTable.getTranslatedExpr(), createTranslated(mid_p1));
  486. OwnedHqlExpr test1 = createBoolExpr(no_lt, LINK(compareVar), getZero());
  487. OwnedHqlExpr test2 = createBoolExpr(no_gt, LINK(compareVar), getZero());
  488. OwnedHqlExpr order = createValue(no_order, LINK(indexType), test.getTranslatedExpr(), LINK(curelem));
  489. BuildCtx loopctx(ctx);
  490. loopctx.addLoop(loopc, NULL, true);
  491. translator.buildAssignToTemp(loopctx, midVar, mid);
  492. translator.buildAssignToTemp(loopctx, compareVar, order);
  493. BuildCtx subctx(loopctx);
  494. IHqlStmt * if1 = subctx.addFilter(test1); // if (test < 0)
  495. translator.buildAssignToTemp(subctx, rightVar, midVar); // right = mid;
  496. subctx.selectElse(if1); // else
  497. IHqlStmt * if2 = subctx.addFilter(test2); // if (test > 0)
  498. translator.buildAssignToTemp(subctx, leftVar, mid_p1); // left = mid + 1;
  499. subctx.selectElse(if2); // else
  500. //generate the default assignment...
  501. translator.buildExprAssign(subctx, target, resultExpr);
  502. subctx.addBreak();
  503. }
  504. }
  505. void HqlCppCaseInfo::buildIntegerSearchMap(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * test)
  506. {
  507. ITypeInfo * compareType = queryCompareType();
  508. HqlExprArray args;
  509. args.append(*createCompareList());
  510. args.append(*LINK(test));
  511. _ATOM func;
  512. if (compareType->isSigned())
  513. {
  514. if (compareType->getSize() > 4)
  515. func = searchTableInteger8Atom;
  516. else
  517. func = searchTableInteger4Atom;
  518. }
  519. else
  520. {
  521. if (compareType->getSize() > 4)
  522. func = searchTableUInteger8Atom;
  523. else
  524. func = searchTableUInteger4Atom;
  525. }
  526. OwnedHqlExpr search = translator.bindFunctionCall(func, args);
  527. OwnedHqlExpr midVar = createVariable(LINK(indexType));
  528. bool includeDefaultInResult = false;
  529. OwnedHqlExpr resultExpr = createResultsExpr(midVar, true, &includeDefaultInResult);
  530. OwnedHqlExpr simpleResult = queryCreateSimpleResultAssign(search, resultExpr);
  531. if (simpleResult)
  532. translator.buildExprAssign(ctx, target, simpleResult);
  533. else
  534. {
  535. ctx.addDeclare(midVar, NULL);
  536. translator.buildAssignToTemp(ctx, midVar, search);
  537. if (includeDefaultInResult)
  538. {
  539. translator.buildExprAssign(ctx, target, resultExpr);
  540. }
  541. else
  542. {
  543. OwnedHqlExpr compare = createBoolExpr(no_ne, LINK(midVar), createNotFoundValue());
  544. BuildCtx subctx(ctx);
  545. IHqlStmt * stmt = subctx.addFilter(compare);
  546. translator.buildExprAssign(subctx, target, resultExpr);
  547. subctx.selectElse(stmt);
  548. translator.buildExprAssign(subctx, target, defaultValue);
  549. }
  550. }
  551. }
  552. void HqlCppCaseInfo::buildSwitchCondition(BuildCtx & ctx, CHqlBoundExpr & bound)
  553. {
  554. OwnedHqlExpr simpleCond = complexCompare ? getSimplifyCompareArg(cond) : LINK(cond);
  555. translator.buildCachedExpr(ctx, simpleCond, bound);
  556. }
  557. void HqlCppCaseInfo::buildSwitchMap(BuildCtx & ctx, const CHqlBoundTarget * target, IHqlExpression * test)
  558. {
  559. bool isCharCompare = (test->queryType()->getTypeCode() == type_string);
  560. LinkedHqlExpr cond = test;
  561. if (isCharCompare)
  562. cond.setown(createValue(no_index, makeCharType(), LINK(test), getZero()));
  563. BuildCtx subctx(ctx);
  564. IHqlStmt * stmt = subctx.addSwitch(cond);
  565. // are all the comparisons against constant values? If so we optimize it...
  566. unsigned sameCount = 0;
  567. ForEachItemIn(idx, pairs)
  568. {
  569. IHqlExpression & cur = pairs.item(idx);
  570. LinkedHqlExpr compare = cur.queryChild(0);
  571. IHqlExpression * branchValue = cur.queryChild(1);
  572. if (isCharCompare)
  573. {
  574. OwnedITypeInfo charType = makeCharType();
  575. IValue * cur = compare->queryValue();
  576. IValue * next = cur->castTo(charType);
  577. compare.setown(createConstant(next));
  578. }
  579. bool same = false;
  580. bool skip = false;
  581. if (idx != pairs.ordinality()-1)
  582. {
  583. IHqlExpression & next = pairs.item(idx+1);
  584. if (next.queryChild(1) == branchValue)
  585. same = true;
  586. //if save item is included twice, remove one so no error
  587. //from the case statement
  588. if (next.queryChild(0) == cur.queryChild(0))
  589. {
  590. skip = true;
  591. #ifdef _DEBUG
  592. throwUnexpected(); // should have been removed as a duplicate
  593. #endif
  594. }
  595. }
  596. if (sameCount >= MAX_NUM_NOBREAK_CASE)
  597. same = false;
  598. if (!skip)
  599. {
  600. subctx.addCase(stmt, compare);
  601. // common up case labels that produce the same result
  602. if (!same)
  603. {
  604. sameCount = 1;
  605. if (target)
  606. translator.buildExprAssign(subctx, *target, branchValue);
  607. else
  608. translator.buildReturn(subctx, branchValue);
  609. }
  610. else
  611. sameCount++;
  612. }
  613. }
  614. if (target)
  615. {
  616. subctx.addDefault(stmt);
  617. translator.buildExprAssign(subctx, *target, defaultValue);
  618. }
  619. else
  620. translator.buildReturn(ctx, defaultValue);
  621. }
  622. void HqlCppCaseInfo::buildGeneralAssign(BuildCtx & ctx, const CHqlBoundTarget & target)
  623. {
  624. unsigned max = pairs.ordinality();
  625. Owned<BuildCtx> subctx = new BuildCtx(ctx);
  626. CHqlBoundExpr pureCond;
  627. if (cond.get())
  628. translator.buildCachedExpr(*subctx, cond, pureCond);
  629. OwnedHqlExpr testMore;
  630. if (max > MAX_NESTED_CASES)
  631. {
  632. //Too many nested blocks cause the compiler indigestion...
  633. Owned<ITypeInfo> t = makeBoolType();
  634. testMore.setown(ctx.getTempDeclare(t, queryBoolExpr(false)));
  635. }
  636. for (unsigned idx = 0; idx < max; idx++)
  637. {
  638. IHqlExpression & cur = pairs.item(idx);
  639. IHqlExpression * curtest = cur.queryChild(0);
  640. IHqlExpression * curvalue = cur.queryChild(1);
  641. OwnedHqlExpr compare;
  642. if (!pureCond.expr)
  643. compare.setown(ensureExprType(curtest, queryBoolType()));
  644. else
  645. compare.setown(createBoolExpr(no_eq, pureCond.getTranslatedExpr(), LINK(curtest)));
  646. if (idx && ((idx % MAX_NESTED_CASES) == 0))
  647. {
  648. translator.buildAssignToTemp(*subctx,testMore,queryBoolExpr(true));
  649. subctx.setown(new BuildCtx(ctx));
  650. subctx->addFilter(testMore);
  651. translator.buildAssignToTemp(*subctx,testMore,queryBoolExpr(false));
  652. }
  653. IHqlStmt * test = translator.buildFilterViaExpr(*subctx, compare);
  654. translator.buildExprAssign(*subctx, target, curvalue);
  655. subctx->selectElse(test);
  656. }
  657. translator.buildExprAssign(*subctx, target, defaultValue);
  658. }
  659. void HqlCppCaseInfo::buildGeneralReturn(BuildCtx & ctx)
  660. {
  661. unsigned max = pairs.ordinality();
  662. CHqlBoundExpr pureCond;
  663. if (cond.get())
  664. translator.buildCachedExpr(ctx, cond, pureCond);
  665. for (unsigned idx = 0; idx < max; idx++)
  666. {
  667. IHqlExpression & cur = pairs.item(idx);
  668. IHqlExpression * curtest = cur.queryChild(0);
  669. IHqlExpression * curvalue = cur.queryChild(1);
  670. OwnedHqlExpr compare;
  671. if (!pureCond.expr)
  672. compare.setown(ensureExprType(curtest, queryBoolType()));
  673. else
  674. compare.setown(createBoolExpr(no_eq, pureCond.getTranslatedExpr(), LINK(curtest)));
  675. BuildCtx subctx(ctx);
  676. translator.buildFilter(subctx, compare);
  677. translator.buildReturn(subctx, curvalue);
  678. }
  679. translator.buildReturn(ctx, defaultValue);
  680. }
  681. bool HqlCppCaseInfo::okToAlwaysEvaluateDefault()
  682. {
  683. return defaultValue->isPure();
  684. }
  685. ITypeInfo * HqlCppCaseInfo::queryCompareType()
  686. {
  687. return cond->queryType()->queryPromotedType();
  688. }
  689. IHqlExpression * HqlCppCaseInfo::createCompareList()
  690. {
  691. //NB: All cases need to have the same type because they are stored in a table
  692. Linked<ITypeInfo> promoted = pairs.item(0).queryChild(0)->queryType();
  693. unsigned max = pairs.ordinality();
  694. for (unsigned idx1 = 1; idx1 < max; idx1++)
  695. {
  696. ITypeInfo * type = pairs.item(idx1).queryChild(0)->queryType();
  697. promoted.setown(getPromotedECLType(promoted, type));
  698. }
  699. HqlExprArray values;
  700. values.ensure(pairs.ordinality());
  701. ForEachItemIn(idx, pairs)
  702. {
  703. IHqlExpression & pair = pairs.item(idx);
  704. IHqlExpression * compare = pair.queryChild(0);
  705. values.append(*ensureExprType(compare, promoted));
  706. }
  707. Linked<ITypeInfo> compareType = queryCompareType();
  708. switch (compareType->getTypeCode())
  709. {
  710. case type_string:
  711. case type_data:
  712. case type_varstring:
  713. case type_qstring:
  714. case type_utf8:
  715. compareType.setown(makePointerType(makeCharType(false)));
  716. break;
  717. case type_unicode:
  718. case type_varunicode:
  719. compareType.setown(makePointerType(makeClassType("UChar")));
  720. break;
  721. }
  722. return createValue(no_list, makeArrayType(compareType.getLink()), values);
  723. }
  724. IHqlExpression * HqlCppCaseInfo::createResultsExpr(IHqlExpression * matchVar, bool canIncludeDefault, bool * includedDefault)
  725. {
  726. if (includedDefault)
  727. *includedDefault = false;
  728. //Look at all the return results and see what relation we can create
  729. //This can generate one of the following:
  730. //1. A single value.
  731. //2. A function of the result. e.g., IN...
  732. //3. A lookup in another table. [ all values are constant ]
  733. //4. A nested map statement
  734. bool areSame = true;
  735. bool areLinear = true;
  736. bool areConstant = true;
  737. __int64 linearStart = 0;
  738. __int64 linearMultiple = 1;
  739. ITypeInfo * retType = resultType;
  740. switch (retType->getTypeCode())
  741. {
  742. case type_int:
  743. case type_boolean:
  744. break;
  745. case type_string:
  746. case type_data:
  747. // areConstant = false; // a temporary hack to stop incorrect table being generated.
  748. areLinear = false;
  749. break;
  750. default:
  751. areLinear = false;
  752. break;
  753. }
  754. IHqlExpression * prevValue = NULL;
  755. HqlExprArray values;
  756. values.ensure(pairs.ordinality());
  757. ForEachItemIn(idx, pairs)
  758. {
  759. IHqlExpression & pair = pairs.item(idx);
  760. IHqlExpression * value = pair.queryChild(1);
  761. IValue * cvalue = value->queryValue();
  762. if (cvalue)
  763. {
  764. if (areLinear)
  765. {
  766. __int64 val = cvalue->getIntValue();
  767. if (idx == 0)
  768. linearStart = val;
  769. else if (idx == 1)
  770. linearMultiple = (val - linearStart);
  771. else if (val != linearStart + idx * linearMultiple)
  772. areLinear = false;
  773. }
  774. }
  775. else
  776. {
  777. areConstant = false;
  778. areLinear = false;
  779. }
  780. if (idx > 0)
  781. {
  782. if (areSame && (prevValue != value))
  783. areSame = false;
  784. }
  785. values.append(*ensureExprType(value, resultType));
  786. prevValue = value;
  787. }
  788. if (areSame)
  789. return LINK(prevValue);
  790. if (areLinear)
  791. {
  792. IHqlExpression * ret = ensureExprType(matchVar, resultType);
  793. if (linearMultiple != 1)
  794. ret = createValue(no_mul, LINK(resultType), ret, createConstant(resultType->castFrom(true, linearMultiple)));
  795. if (linearStart != 0)
  796. ret = createValue(no_add, LINK(resultType), ret, createConstant(resultType->castFrom(true, linearStart)));
  797. return ret;
  798. }
  799. unsigned firstMatchEntry = 0;
  800. if (canIncludeDefault)
  801. {
  802. //If all the values are constant, then can add the default as an extra 0th entry, because -1 will be the index for the default
  803. if (areConstant && defaultValue->isConstant() && defaultValue->queryType() == values.item(0).queryType())
  804. {
  805. firstMatchEntry = 1;
  806. values.add(*LINK(defaultValue), 0);
  807. *includedDefault = true;
  808. }
  809. }
  810. // easy way to create a value list...
  811. ITypeInfo * storeType = getArrayElementType(retType);
  812. OwnedHqlExpr newlist = createValue(no_list, makeSetType(storeType), values);
  813. if (areConstant && canBuildStaticList(resultType))
  814. {
  815. IHqlExpression * index = adjustValue(matchVar, 1+firstMatchEntry);
  816. return createValue(no_index, LINK(retType), LINK(newlist), index, createAttribute(noBoundCheckAtom));
  817. }
  818. //Need to generate a case (switch integer case 1: ..... )
  819. HqlExprArray choosePairs;
  820. cvtChooseListToPairs(choosePairs, newlist, 0);
  821. IHqlExpression * caseExpr = createOpenValue(no_case, LINK(retType));
  822. caseExpr->addOperand(LINK(matchVar));
  823. ForEachItemIn(idx2, choosePairs)
  824. caseExpr->addOperand(&choosePairs.item(idx2));
  825. choosePairs.kill(true);
  826. caseExpr->addOperand(LINK(defaultValue));
  827. return caseExpr->closeExpr();
  828. }
  829. void HqlCppCaseInfo::generateCompareVar(BuildCtx & ctx, IHqlExpression * target, CHqlBoundExpr & test, IHqlExpression * other)
  830. {
  831. OwnedHqlExpr compare = createValue(no_order, test.getTranslatedExpr(), LINK(other));
  832. translator.buildAssignToTemp(ctx, target, compare);
  833. }
  834. unsigned HqlCppCaseInfo::getNumPairs()
  835. {
  836. return pairs.ordinality();
  837. }
  838. bool HqlCppCaseInfo::hasLibraryChop()
  839. {
  840. ITypeInfo * compareType = queryCompareType();
  841. type_t ctc = compareType->getTypeCode();
  842. switch (ctc)
  843. {
  844. case type_data:
  845. return canBuildStaticList(promotedElementType);
  846. case type_string:
  847. case type_varstring:
  848. case type_qstring:
  849. case type_unicode:
  850. case type_varunicode:
  851. case type_utf8:
  852. return true;
  853. }
  854. return false;
  855. }
  856. void HqlCppCaseInfo::processBranches()
  857. {
  858. sortPairs();
  859. removeDuplicates();
  860. promoteTypes();
  861. }
  862. void HqlCppCaseInfo::promoteTypes()
  863. {
  864. Owned<ITypeInfo> promoted = pairs.item(0).queryChild(0)->getType();
  865. unsigned max = pairs.ordinality();
  866. for (unsigned idx1 = 1; idx1 < max; idx1++)
  867. {
  868. ITypeInfo * type = pairs.item(idx1).queryChild(0)->queryType();
  869. if (isStringType(promoted) && isStringType(type))
  870. {
  871. if (promoted->getStringLen() != type->getStringLen())
  872. {
  873. promoted.setown(::getPromotedECLType(promoted, type));
  874. promoted.setown(getStretchedType(UNKNOWN_LENGTH, promoted));
  875. }
  876. }
  877. promoted.setown(::getPromotedECLType(promoted, type));
  878. }
  879. promotedElementType.set(promoted);
  880. if (isStringType(promoted))
  881. promoted.setown(getStretchedType(UNKNOWN_LENGTH, promoted));
  882. ITypeInfo * testType = queryCompareType();
  883. if ((testType->queryCharset() != promoted->queryCharset()) || (testType->queryLocale() != promoted->queryLocale()))
  884. cond.setown(ensureExprType(cond, promoted));
  885. }
  886. bool HqlCppCaseInfo::canBuildArrayLookup(const CHqlBoundExpr & test)
  887. {
  888. ITypeInfo * condType = test.queryType()->queryPromotedType();
  889. //MORE: Also support this for high density tables that don't start at 0... - checking upper and lower bounds
  890. unsigned bitSize = condType->getBitSize();
  891. if (constantValues && (bitSize && (bitSize <= 8) && !condType->isSigned()))
  892. {
  893. unsigned limit = (1 << bitSize);
  894. //use case if enough items, or above a certain density...
  895. if (pairs.ordinality() * 100 >= limit * SWITCH_TABLE_DENSITY_THRESHOLD)
  896. {
  897. if ((condType->getTypeCode() == type_int) || (condType->getTypeCode() == type_string))
  898. return true;
  899. }
  900. }
  901. return false;
  902. }
  903. bool HqlCppCaseInfo::queryBuildArrayLookup(BuildCtx & ctx, const CHqlBoundTarget & target, const CHqlBoundExpr & test)
  904. {
  905. if (canBuildArrayLookup(test) && canBuildStaticList(resultType))
  906. {
  907. //MORE: Also support this for high density tables that don't start at 0... - checking upper and lower bounds
  908. ITypeInfo * condType = test.queryType()->queryPromotedType();
  909. unsigned bitSize = condType->getBitSize();
  910. unsigned limit = (1 << bitSize);
  911. BuildCtx subctx(ctx);
  912. OwnedHqlExpr ret = buildIndexedMap(subctx, test.expr, 0, limit-1);
  913. translator.buildExprAssign(ctx, target, ret);
  914. return true;
  915. }
  916. return false;
  917. }
  918. void HqlCppCaseInfo::removeDuplicates()
  919. {
  920. unsigned num = pairs.ordinality();
  921. if (num > 1)
  922. {
  923. num--;
  924. while (num--)
  925. {
  926. IHqlExpression & cur = pairs.item(num);
  927. IHqlExpression & next = pairs.item(num+1);
  928. if (cur.queryChild(0) == next.queryChild(0))
  929. {
  930. if (cur.queryChild(1) == next.queryChild(1))
  931. pairs.remove(num+1);
  932. else
  933. {
  934. // we need to keep the first in the original list.... Horrid, but it works...
  935. unsigned off1 = originalPairs.find(cur);
  936. unsigned off2 = originalPairs.find(next);
  937. assertex(off1 != NotFound && off2 != NotFound);
  938. if (off1 < off2)
  939. pairs.remove(num+1);
  940. else
  941. pairs.remove(num);
  942. }
  943. }
  944. }
  945. }
  946. }
  947. IHqlExpression * HqlCppCaseInfo::queryCreateSimpleResultAssign(IHqlExpression * search, IHqlExpression * resultExpr)
  948. {
  949. IHqlExpression * trueExpr = queryBoolExpr(true);
  950. IHqlExpression * falseExpr = queryBoolExpr(false);
  951. if (resultExpr == trueExpr && defaultValue == falseExpr)
  952. return createBoolExpr(no_ne, LINK(search), createNotFoundValue());
  953. if (resultExpr == falseExpr && defaultValue == trueExpr)
  954. return createBoolExpr(no_eq, LINK(search), createNotFoundValue());
  955. return NULL;
  956. }
  957. IHqlExpression * HqlCppCaseInfo::queryCompare(unsigned index)
  958. {
  959. return pairs.item(index).queryChild(0);
  960. }
  961. IHqlExpression * HqlCppCaseInfo::queryReturn(unsigned index)
  962. {
  963. return pairs.item(index).queryChild(1);
  964. }
  965. void HqlCppCaseInfo::setCond(IHqlExpression * expr)
  966. {
  967. cond.set(expr);
  968. if (isCompare3Valued(expr->queryType()))
  969. complexCompare = true;
  970. }
  971. void HqlCppCaseInfo::setDefault(IHqlExpression * expr)
  972. {
  973. defaultValue.set(expr);
  974. }
  975. void HqlCppCaseInfo::sortPairs()
  976. {
  977. appendArray(originalPairs, pairs);
  978. pairs.sort(comparePair);
  979. }
  980. void HqlCppCaseInfo::updateResultType(IHqlExpression * expr)
  981. {
  982. ITypeInfo * curResultType = expr->queryType();
  983. if (resultType)
  984. resultType.setown(::getPromotedECLType(resultType, curResultType));
  985. else
  986. resultType.set(curResultType);
  987. }