@@ -210,6 +210,14 @@
Loading
210 210
            }
211 211
          }
212 212
213 +
          if (this->modes->isModeEnabled(triton::modes::AST_OPTIMIZATIONS)) {
214 +
            /* Optimization: concatenate extractions in one if possible */
215 +
            auto n = this->simplify_concat(std::vector<SharedAbstractNode>(exprs.begin(), exprs.end()));
216 +
            if (n) {
217 +
              return n;
218 +
            }
219 +
          }
220 +
213 221
          return this->collect(node);
214 222
        }
215 223
@@ -322,6 +330,9 @@
Loading
322 330
        TRITON_EXPORT std::ostream& print(std::ostream& stream, AbstractNode* node);
323 331
324 332
      private:
333 +
        //! Return simplified concatenation.
334 +
        SharedAbstractNode simplify_concat(std::vector<SharedAbstractNode> exprs);
335 +
325 336
        //! Return simplified extraction.
326 337
        SharedAbstractNode simplify_extract(triton::uint32 high, triton::uint32 low, const SharedAbstractNode& expr);
327 338
    };

@@ -749,6 +749,14 @@
Loading
749 749
        }
750 750
      }
751 751
752 +
      if (this->modes->isModeEnabled(triton::modes::AST_OPTIMIZATIONS)) {
753 +
        /* Optimization: concatenate extractions in one if possible */
754 +
        auto n = this->simplify_concat(std::vector<SharedAbstractNode>({expr1, expr2}));
755 +
        if (n) {
756 +
          return n;
757 +
        }
758 +
      }
759 +
752 760
      return this->collect(node);
753 761
    }
754 762
@@ -1059,6 +1067,93 @@
Loading
1059 1067
    }
1060 1068
1061 1069
1070 +
    SharedAbstractNode AstContext::simplify_concat(std::vector<SharedAbstractNode> exprs) {
1071 +
      /*
1072 +
       * Optimization: concatenate extractions in one if possible. We are
1073 +
       * trying to find out whether this is a concatenation of sequential
1074 +
       * extractions from the same AST. Thus, we can make only one extraction.
1075 +
       *
1076 +
       * (concat ((_ extract 31 24) a) ((_ extract 23 16) a)
1077 +
       *         ((_ extract 15 8) a) ((_ extract 7 0) a)) =>
1078 +
       * ((_ extract 31 0) a)
1079 +
       *
1080 +
       * So, we are examining whether we can replace concatenation with one
1081 +
       * extraction ((_ extract high low) ast_ref).
1082 +
       **/
1083 +
      uint32 high = 0;                  // target extraction upper bound
1084 +
      uint32 low = 1;                   // target extraction lower bound
1085 +
      SharedAbstractNode ast_ref = 0;   // target AST to extract from
1086 +
      SharedAbstractNode ast_node = 0;  // ast_ref with unrolled references
1087 +
1088 +
      /* Try to join all extractions into one from the right to the left */
1089 +
      while (!exprs.empty()) {
1090 +
        /* Get the right most node */
1091 +
        auto n = exprs.back();
1092 +
        exprs.pop_back();
1093 +
1094 +
        /* Unroll references */
1095 +
        while (n->getType() == REFERENCE_NODE) {
1096 +
          auto ref = reinterpret_cast<ReferenceNode*>(n.get());
1097 +
          n = ref->getSymbolicExpression()->getAst();
1098 +
        }
1099 +
1100 +
        if (n->getType() == CONCAT_NODE) {
1101 +
          /* Append concatenation children to the right */
1102 +
          for (const auto& part : n->getChildren()) {
1103 +
            exprs.push_back(part);
1104 +
          }
1105 +
          continue;
1106 +
        }
1107 +
1108 +
        if (n->getType() != EXTRACT_NODE) {
1109 +
          /* We cannot optimize if at least one node is not an extract */
1110 +
          return 0;
1111 +
        }
1112 +
1113 +
        /* Get extraction arguments */
1114 +
        const auto& childs = n->getChildren();
1115 +
        auto hi = reinterpret_cast<IntegerNode*>(childs[0].get())->getInteger().convert_to<uint32>();
1116 +
        auto lo = reinterpret_cast<IntegerNode*>(childs[1].get())->getInteger().convert_to<uint32>();
1117 +
        if (hi < lo) {
1118 +
          return 0;
1119 +
        }
1120 +
        n = childs[2];
1121 +
1122 +
        /* Unroll references */
1123 +
        while (n->getType() == REFERENCE_NODE) {
1124 +
          auto ref = reinterpret_cast<ReferenceNode*>(n.get());
1125 +
          n = ref->getSymbolicExpression()->getAst();
1126 +
        }
1127 +
1128 +
        if (!ast_ref) {
1129 +
          /* First found extraction node */
1130 +
          high = hi;
1131 +
          low = lo;
1132 +
          ast_ref = childs[2];
1133 +
          ast_node = n;
1134 +
          continue;
1135 +
        }
1136 +
1137 +
        /*
1138 +
         * Check that unrolled target AST is equal to extraction node child.
1139 +
         * Also, check that extraction lower bound connects with target
1140 +
         * extraction upper bound.
1141 +
         **/
1142 +
        if (high + 1 != lo || !n->equalTo(ast_node)) {
1143 +
          return 0;
1144 +
        }
1145 +
        high = hi;
1146 +
      }
1147 +
1148 +
      if (high < low) {
1149 +
        return 0;
1150 +
      }
1151 +
1152 +
      /* Perform target extraction */
1153 +
      return this->extract(high, low, ast_ref);
1154 +
    }
1155 +
1156 +
1062 1157
    SharedAbstractNode AstContext::simplify_extract(triton::uint32 high, triton::uint32 low, const SharedAbstractNode& expr) {
1063 1158
      auto size = expr->getBitvectorSize();
1064 1159
Files Coverage
src/libtriton 86.15%
Project Totals (107 files) 86.15%
2815.3
TRAVIS_OS_NAME=linux
1
coverage:
2
  range: 70..100
3
  round: nearest
4
  precision: 2
5

6
ignore:
7
  - "**/examples/cpp" # ignore folders and all its contents
8
  - "/src/tracer"     # ignore folders and all its contents
9
  - "**/*.spec"       # glob accepted
10

11
comment: false
Sunburst
The inner-most circle is the entire project, moving away from the center are folders then, finally, a single file. The size and color of each slice is representing the number of statements and the coverage, respectively.
Icicle
The top section represents the entire project. Proceeding with folders and finally individual files. The size and color of each slice is representing the number of statements and the coverage, respectively.
Grid
Each block represents a single file in the project. The size and color of each block is represented by the number of statements and the coverage, respectively.
Loading