瀏覽代碼

HPCC-12028 Improve the code generated for ifblocks

Signed-off-by: Gavin Halliday <gavin.halliday@lexisnexis.com>
Gavin Halliday 11 年之前
父節點
當前提交
88df058617
共有 4 個文件被更改,包括 133 次插入11 次删除
  1. 92 0
      ecl/hql/hqlfold.cpp
  2. 2 0
      ecl/hql/hqlfold.hpp
  3. 35 7
      ecl/hqlcpp/hqltcppc.cpp
  4. 4 4
      ecl/hqlcpp/hqltcppc.ipp

+ 92 - 0
ecl/hql/hqlfold.cpp

@@ -6264,3 +6264,95 @@ extern HQLFOLD_API void quickFoldExpressions(HqlExprArray & target, const HqlExp
     ForEachItemIn(i, source)
         target.append(*transformer.transform(&source.item(i)));
 }
+
+//--------------------------------------------------------------------------------------------------------------------
+
+static bool valueInList(IHqlExpression * search, IHqlExpression * list)
+{
+    if (list->getOperator() != no_list)
+        return false;
+
+    ForEachChild(i, list)
+    {
+        if (search == list->queryChild(i))
+            return true;
+    }
+    return false;
+}
+
+static bool valueNotInList(IHqlExpression * search, IHqlExpression * list)
+{
+    if (list->getOperator() != no_list)
+        return false;
+
+    IValue * value = search->queryValue();
+    if (!value)
+        return false; // can't tell
+
+    ForEachChild(i, list)
+    {
+        IHqlExpression * cur = list->queryChild(i);
+        IValue * curValue = cur->queryValue();
+        if (!curValue || value == curValue)
+            return false;
+    }
+    return true;
+}
+
+
+//Is it guaranteed that both conditions cannot be true at the same time.  Avoid false positivies.
+//Don't try and catch all examples, just the most common possibilities.
+//This could be improved over time....
+extern HQLFOLD_API bool areExclusiveConditions(IHqlExpression * left, IHqlExpression * right)
+{
+    node_operator leftOp = left->getOperator();
+    node_operator rightOp = right->getOperator();
+
+    // Check for x = constant1, x = constant2, constant1 != constant2
+    if ((leftOp == no_eq) && (rightOp == no_eq))
+    {
+        if (left->queryChild(0) == right->queryChild(0))
+        {
+            //Can only really be sure if comparing against constants.
+            IValue * leftValue = left->queryChild(1)->queryValue();
+            IValue * rightValue = right->queryChild(1)->queryValue();
+            return (leftValue && rightValue && leftValue != rightValue);
+        }
+        return false;
+    }
+
+    // Check for NOT x, x
+    if ((leftOp == no_not) && (left->queryChild(0) == right))
+        return true;
+
+    // Check for x, NOT x
+    if ((rightOp == no_not) && (right->queryChild(0) == left))
+        return true;
+
+    // two tests against the same condition (could also pass in here if both NULL..)
+    if (left->queryChild(0) == right->queryChild(0))
+    {
+        // Check for x <op> y, x !<op> y  - no need for y to be a constant.
+        if (leftOp == getInverseOp(rightOp))
+        {
+            return left->queryChild(1) == right->queryChild(1);
+        }
+
+        // Unusual, but occured in the main example I was trying to improve
+        // x = c1, x not in [c1, ....]
+        // x = c1, x in [c2, c3, c4, c5]
+        if ((leftOp == no_eq) && (rightOp == no_notin))
+            return valueInList(left->queryChild(1),  right->queryChild(1));
+
+        if ((leftOp == no_eq) && (rightOp == no_in))
+            return valueNotInList(left->queryChild(1),  right->queryChild(1));
+
+        if ((rightOp == no_eq) && (leftOp == no_notin))
+            return valueInList(right->queryChild(1),  left->queryChild(1));
+
+        if ((rightOp == no_eq) && (leftOp == no_in))
+            return valueNotInList(right->queryChild(1),  left->queryChild(1));
+    }
+
+    return false;
+}

+ 2 - 0
ecl/hql/hqlfold.hpp

@@ -58,4 +58,6 @@ extern HQLFOLD_API void foldHqlExpression(IErrorReceiver & errorProcessor, HqlEx
 extern HQLFOLD_API IHqlExpression * lowerCaseHqlExpr(IHqlExpression * expr);
 extern HQLFOLD_API IHqlExpression * foldExprIfConstant(IHqlExpression * expr);
 
+extern HQLFOLD_API bool areExclusiveConditions(IHqlExpression * left, IHqlExpression * right);
+
 #endif

+ 35 - 7
ecl/hqlcpp/hqltcppc.cpp

@@ -262,6 +262,11 @@ void CMemberInfo::calcCachedSize(const SizeStruct & offset, SizeStruct & sizeSel
 }
 
 
+bool CMemberInfo::checkCompatibleIfBlock(HqlExprCopyArray & conditions)
+{
+    return false;
+}
+
 StringBuffer & CMemberInfo::expandSelectPathText(StringBuffer & out, bool isLast) const
 {
     bool isField = (column->getOperator() == no_field);
@@ -300,14 +305,27 @@ void CContainerInfo::calcAllCachedOffsets()
     }
 }
 
-void CContainerInfo::calcCachedChildrenOffsets(SizeStruct & offset, SizeStruct & sizeSelf)
+void CContainerInfo::calcCachedChildrenOffsets(const SizeStruct & startOffset, SizeStruct & sizeSelf)
 {
+    //Optimize one special case of ifblocks.
+    //Sometimes you have a header with some fields, followed by a set of mutually exlusive ifblocks.
+    //Spot any trailing mutually exclusive ifblocks and don't update
+    HqlExprCopyArray conditions;
+    unsigned maxOffsetUpdate = children.ordinality();
+    while (maxOffsetUpdate > 0)
+    {
+        CMemberInfo & cur = children.item(maxOffsetUpdate-1);
+        if (!cur.checkCompatibleIfBlock(conditions))
+            break;
+        maxOffsetUpdate--;
+    }
+
+    SizeStruct offset(startOffset);
     ForEachItemIn(idx, children)
     {
         CMemberInfo & cur = children.item(idx);
 
         SizeStruct sizeChild(offset.querySelf());
-        SizeStruct maxSizeChild(offset.querySelf());
 
         cur.calcCachedOffsets(offset, sizeChild);
         if (offset.isWorthCommoning())
@@ -316,7 +334,8 @@ void CContainerInfo::calcCachedChildrenOffsets(SizeStruct & offset, SizeStruct &
             offset.forceToTemp(no_offsetof, child);
         }
         sizeSelf.add(sizeChild);
-        offset.add(sizeChild);
+        if (idx < maxOffsetUpdate)
+            offset.add(sizeChild);
     }
 }
 
@@ -370,8 +389,7 @@ unsigned CContainerInfo::getTotalMinimumSize()
 
 void CIfBlockInfo::calcCachedSize(const SizeStruct & offset, SizeStruct & sizeSelf)
 {
-    SizeStruct childOffset(offset);
-    calcCachedChildrenOffsets(childOffset, cachedSize);
+    calcCachedChildrenOffsets(offset, cachedSize);
 
     if (cachedSize.isFixedSize())
         sizeSelf.set(cachedSize);
@@ -383,6 +401,17 @@ void CIfBlockInfo::calcCachedSize(const SizeStruct & offset, SizeStruct & sizeSe
     }
 }
 
+bool CIfBlockInfo::checkCompatibleIfBlock(HqlExprCopyArray & conditions)
+{
+    ForEachItemIn(i, conditions)
+    {
+        if (!areExclusiveConditions(condition, &conditions.item(i)))
+            return false;
+    }
+    conditions.append(*condition);
+    return true;
+}
+
 unsigned CIfBlockInfo::getTotalFixedSize()
 {
     if (alwaysPresent)
@@ -401,8 +430,7 @@ void CBitfieldContainerInfo::calcCachedSize(const SizeStruct & offset, SizeStruc
     sizeSelf.set(cachedSize);
 
     SizeStruct sizeBitfields(sizeSelf.querySelf());
-    SizeStruct offsetBitfields(offset);
-    calcCachedChildrenOffsets(offsetBitfields, sizeBitfields);
+    calcCachedChildrenOffsets(offset, sizeBitfields);
     assertex(sizeBitfields.isFixedSize() && sizeBitfields.getFixedSize() == 0);
 }
 

+ 4 - 4
ecl/hqlcpp/hqltcppc.ipp

@@ -100,7 +100,8 @@ public:
     virtual unsigned getTotalMinimumSize();
     virtual unsigned getContainerTrailingFixed();
     virtual bool modifyColumn(HqlCppTranslator & translator, BuildCtx & ctx, IReferenceSelector * selector, IHqlExpression * value, node_operator op) { return false; }
-
+    virtual bool checkCompatibleIfBlock(HqlExprCopyArray & conditions);
+    
     void addVariableSize(size32_t varMinSize, SizeStruct & size);
     void getXPath(StringBuffer & out);
     StringBuffer & expandSelectPathText(StringBuffer & out, bool isLast) const;
@@ -202,9 +203,7 @@ public:
 
 protected:
     virtual void registerChild(CMemberInfo * child);
-    void calcCachedChildrenOffsets(SizeStruct & offset, SizeStruct & sizeSelf);
-//  void gatherChildrenFixedSize(SizeStruct & target);
-
+    void calcCachedChildrenOffsets(const SizeStruct & startOffset, SizeStruct & sizeSelf);
 
 protected:
     CMemberInfoArray    children;
@@ -251,6 +250,7 @@ public:
     virtual void setColumn(HqlCppTranslator & translator, BuildCtx & ctx, IReferenceSelector * selector, IHqlExpression * value);
 
     virtual void calcCachedSize(const SizeStruct & offset, SizeStruct & sizeSelf);
+    virtual bool checkCompatibleIfBlock(HqlExprCopyArray & conditions);
     virtual IHqlExpression * getCondition(BuildCtx & ctx);
     virtual bool isConditional();
     virtual bool isFixedSize()              { return false; }