From c3f1f886b46c3d8cac5dc85b405582078f6cfd26 Mon Sep 17 00:00:00 2001
From: BenceJanosSzabo <bence.janos.szabo@ericsson.com>
Date: Fri, 16 Sep 2016 15:23:19 +0200
Subject: [PATCH]  optimize code generated for select statements (Bug 500062)

Change-Id: Ic682a96fb26a9e78978ee7ce42d3f972c8ddc073
Signed-off-by: BenceJanosSzabo <bence.janos.szabo@ericsson.com>
---
 compiler2/ttcn3/Statement.cc                  | 113 +++++++++++++++++-
 compiler2/ttcn3/Statement.hh                  |  12 +-
 regression_test/basicStatem/TbasicStatem.ttcn |   5 +
 3 files changed, 125 insertions(+), 5 deletions(-)

diff --git a/compiler2/ttcn3/Statement.cc b/compiler2/ttcn3/Statement.cc
index c5fb0b526..bb7ae1bc6 100644
--- a/compiler2/ttcn3/Statement.cc
+++ b/compiler2/ttcn3/Statement.cc
@@ -6006,7 +6006,25 @@ error:
       str = mputstr(str, "{\n");
       str = mputstr(str, expr_init);
     }
-    str=select.scs->generate_code(str, tmp_prefix.c_str(), expr_name);
+    
+    // Calculate the head expression only once
+    const string& tmp_id = my_sb->get_scope_mod_gen()->get_temporary_id();
+    str = mputprintf(str, "const %s &%s = %s;\n",
+      select.expr->get_my_governor()->get_genname_value(select.expr->get_my_scope()).c_str(),
+      tmp_id.c_str(),
+      expr_name);
+    // We generate different code if the head is an integer and all the branches
+    // are foldable
+    bool int_gen_code = false;
+    if (select.expr->get_my_governor()->is_compatible_tt(Type::T_INT, select.expr->is_asn1())) {
+      int_gen_code = select.scs->foldable_branches();
+    }
+    if (int_gen_code) {
+      str=select.scs->generate_code_switch(str, tmp_id.c_str());
+    }
+    else {
+      str=select.scs->generate_code(str, tmp_prefix.c_str(), tmp_id.c_str());
+    }
     Free(expr_name);
     if (expr_init[0]) str=mputstr(str, "}\n");
     Free(expr_init);
@@ -6358,8 +6376,28 @@ error:
     const string& tmp_prefix = my_sb->get_scope_mod_gen()->get_temporary_id();
     char *expr_init=memptystr();
     char *expr_name=select.expr->generate_code_tmp(0, expr_init);
-    select.scs->ilt_generate_code(ilt, tmp_prefix.c_str(),
-                                  expr_init, expr_name);
+    
+    // Calculate the head expression only once
+    const string& tmp_id = my_sb->get_scope_mod_gen()->get_temporary_id();
+    char * head_expr = mputprintf(head_expr, "const %s &%s = %s;\n",
+      select.expr->get_my_governor()->get_genname_value(select.expr->get_my_scope()).c_str(),
+      tmp_id.c_str(),
+      expr_name);
+
+    // We generate different code if the head is an integer and all the branches
+    // are foldable
+    bool int_gen_code = false;
+    if (select.expr->get_my_governor()->is_compatible_tt(Type::T_INT, select.expr->is_asn1())) {
+      int_gen_code = select.scs->foldable_branches();
+    }
+    if (int_gen_code) {
+      select.scs->ilt_generate_code_switch(ilt, expr_init, head_expr, tmp_id.c_str());
+    }
+    else {
+      select.scs->ilt_generate_code(ilt, tmp_prefix.c_str(),
+                                  expr_init, head_expr, tmp_id.c_str());
+    }
+    Free(head_expr);
     Free(expr_name);
     Free(expr_init);
   }
@@ -10632,6 +10670,27 @@ error:
     }
     return str;
   }
+  
+  char* SelectCase::generate_code_case(char *str, bool&else_branch) {
+    if (tis != NULL) {
+      for (size_t i = 0; i < tis->get_nof_tis(); i++) {
+        str = mputprintf(str, "case(");
+        expression_struct expr;
+        Code::init_expr(&expr);
+        tis->get_ti_byIndex(i)->get_specific_value()->generate_code_expr(&expr);
+        str = mputprintf(str, "%s):\n", expr.expr);
+        Code::free_expr(&expr);
+      }
+    } else {
+      else_branch = true;
+      str = mputstr(str, "default:\n"); // The else branch
+    }
+    
+    str = mputstr(str, "{\n");
+    str = block->generate_code(str);
+    str = mputstr(str, "break;\n}\n");
+    return str;
+  }
 
   /** \todo review */
   char* SelectCase::generate_code_stmt(char *str, const char *tmp_prefix,
@@ -10763,6 +10822,22 @@ error:
       if(scs[i]->get_block()->has_receiving_stmt()) return true;
     return false;
   }
+  
+  bool SelectCases::foldable_branches() const {
+    for(size_t i=0; i<scs.size(); i++) {
+      TemplateInstances* tis = scs[i]->get_tis();
+      if (tis == NULL) { // the else brach
+        continue;
+      }
+      for(size_t j=0; j<tis->get_nof_tis(); j++) {
+        Value * v = tis->get_ti_byIndex(j)->get_specific_value();
+        if (v == NULL || v->is_unfoldable()) {
+          return false;
+        }
+      }
+    }
+    return true;
+  }
 
   /** \todo review */
   void SelectCases::chk(Type *p_gov)
@@ -10802,9 +10877,22 @@ error:
     str=mputprintf(str, "%s_end: /* empty */;\n", tmp_prefix);
     return str;
   }
+  
+  char* SelectCases::generate_code_switch(char *str, const char *expr_name)
+  {
+    bool else_branch=false;
+    str=mputprintf(str, "switch(%s.get_long_long_val()) {\n", expr_name);
+    for(size_t i=0; i<scs.size(); i++) {
+      str=scs[i]->generate_code_case(str, else_branch);
+      if(else_branch) break;
+    }
+    str=mputprintf(str, "};");
+    return str;
+  }
 
   void SelectCases::ilt_generate_code(ILT *ilt, const char *tmp_prefix,
                                       const char *expr_init,
+                                      const char *head_expr,
                                       const char *expr_name)
   {
     char*& str=ilt->get_out_branches();
@@ -10812,6 +10900,7 @@ error:
       str=mputstr(str, "{\n"); // (1)
       str=mputstr(str, expr_init);
     }
+    str=mputstr(str, head_expr);
     bool unreach=false;
     for(size_t i=0; i<scs.size(); i++) {
       if(unreach) break;
@@ -10826,6 +10915,24 @@ error:
     }
     str=mputprintf(str, "%s_end:\n", tmp_prefix);
   }
+  
+  void SelectCases::ilt_generate_code_switch(ILT *ilt, const char *expr_init, const char *head_expr, const char *expr_name)
+  {
+    char*& str=ilt->get_out_branches();
+    if(expr_init[0]) {
+        str=mputstr(str, "{\n");
+        str=mputstr(str, expr_init);
+    }
+    str=mputstr(str, head_expr);
+    bool else_branch=false;
+    str=mputprintf(str, "switch(%s.get_long_long_val()) {\n", expr_name);
+    for(size_t i=0; i<scs.size(); i++) {
+      str=scs[i]->generate_code_case(str, else_branch);
+      if(else_branch) break;
+    }
+    str=mputprintf(str, "};");
+    if (expr_init[0]) str=mputstr(str, "}\n");
+  }
 
   void SelectCases::set_parent_path(WithAttribPath* p_path) {
     for (size_t i = 0; i < scs.size(); i++)
diff --git a/compiler2/ttcn3/Statement.hh b/compiler2/ttcn3/Statement.hh
index 3c81265c7..72df3a3aa 100644
--- a/compiler2/ttcn3/Statement.hh
+++ b/compiler2/ttcn3/Statement.hh
@@ -1335,6 +1335,7 @@ namespace Ttcn {
     void set_code_section(GovernedSimple::code_section_t p_code_section);
     char* generate_code_if(char *str, const char *tmp_prefix,
                            const char *expr_name, size_t idx, bool& unreach);
+    char* generate_code_case(char *str, bool& else_branch);
     char* generate_code_stmt(char *str, const char *tmp_prefix,
                              size_t idx, bool& unreach);
     void ilt_generate_code_stmt(ILT *ilt, const char *tmp_prefix,
@@ -1369,6 +1370,7 @@ namespace Ttcn {
     void set_my_laic_stmt(AltGuards *p_ags, Statement *p_loop_stmt);
     StatementBlock::returnstatus_t has_return() const;
     bool has_receiving_stmt() const;
+    bool foldable_branches() const;
     /* checking functions */
     /** p_gov is the governor type of select expression */
     void chk(Type *p_gov);
@@ -1379,9 +1381,15 @@ namespace Ttcn {
      *  templates to \a p_code_section. */
     void set_code_section(GovernedSimple::code_section_t p_code_section);
     char *generate_code(char *str, const char *tmp_prefix,
-                        const char *expr_name);
+                        const char *expr_name);   
     void ilt_generate_code(ILT *ilt, const char *tmp_prefix,
-                           const char *expr_init, const char *expr_name);
+                           const char *expr_init, const char *head_expr,
+                           const char *expr_name);
+    /** generates code with switch c++ statement only for integer 
+     *  compatible types*/
+    char *generate_code_switch(char *str, const char *expr_name);
+    void ilt_generate_code_switch(ILT *ilt, const char *expr_init, const char *head_expr, const char *expr_name);
+    
 
     /** Needed by implicit omit. Pushes attrib path down to definitions
      */
diff --git a/regression_test/basicStatem/TbasicStatem.ttcn b/regression_test/basicStatem/TbasicStatem.ttcn
index bf3bafdfd..32112214e 100644
--- a/regression_test/basicStatem/TbasicStatem.ttcn
+++ b/regression_test/basicStatem/TbasicStatem.ttcn
@@ -103,6 +103,11 @@ select (int1) {
  case (11,int2,4) { setverdict(pass); }
  case else { setverdict(inconc); }
 }
+select (int1 + int2) {
+ case (3,0) { setverdict(fail); }
+ case (11,4) { setverdict(pass); }
+ case else { setverdict(inconc); }
+}
 var octetstring octet1, octet2;
 octet1:= 'A9'O;
 octet2:= '1267FD'O;
-- 
GitLab