From 928f95a307f82639aeec756be01a9d6c8bc8c151 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fredrik=20H=C3=BCbinette=20=28Hubbe=29?= <hubbe@hubbe.net>
Date: Thu, 30 Nov 2000 17:13:46 -0800
Subject: [PATCH] branch unwinding implemented, will help performance of loops
 using BREAK a lot

Rev: src/docode.c:1.85
Rev: src/opcodes.h:1.7
Rev: src/peep.c:1.41
Rev: src/peep.h:1.7
Rev: src/peep.in:1.42
---
 src/docode.c  |  90 +++++++++++++++++++++++-------
 src/opcodes.h |   6 +-
 src/peep.c    | 149 +++++++++++++++++++++++++-------------------------
 src/peep.h    |  14 ++++-
 src/peep.in   |  13 ++++-
 5 files changed, 172 insertions(+), 100 deletions(-)

diff --git a/src/docode.c b/src/docode.c
index 0a3023e430..01b2337688 100644
--- a/src/docode.c
+++ b/src/docode.c
@@ -5,7 +5,7 @@
 \*/
 /**/
 #include "global.h"
-RCSID("$Id: docode.c,v 1.84 2000/11/08 20:03:45 hubbe Exp $");
+RCSID("$Id: docode.c,v 1.85 2000/12/01 01:13:43 hubbe Exp $");
 #include "las.h"
 #include "program.h"
 #include "pike_types.h"
@@ -60,7 +60,56 @@ int do_jump(int token,INT32 lbl)
   return lbl;
 }
 
-#define ins_label(L) do_jump(F_LABEL, L)
+
+#define LBLCACHESIZE 4711
+#define CURRENT_INSTR ((long)instrbuf.s.len / (long)sizeof(p_instr))
+#define MAX_UNWIND 100
+
+static int lbl_cache[LBLCACHESIZE];
+
+int do_branch(INT32 lbl)
+{
+  if(lbl==-1)
+  {
+    lbl=alloc_label();
+  }else{
+    INT32 last,pos=lbl_cache[lbl % LBLCACHESIZE];
+    if(pos < (last=CURRENT_INSTR) &&  (CURRENT_INSTR - pos) < MAX_UNWIND)
+    {
+#define BUF ((p_instr *)instrbuf.s.str)
+      if(BUF[pos].opcode == F_LABEL && BUF[pos].arg == lbl)
+      {
+	for(;pos < last;pos++)
+	{
+	  if(BUF[pos].opcode != F_LABEL)
+	  {
+	    insert_opcode2(BUF[pos].opcode,
+			   BUF[pos].arg,
+			   BUF[pos].arg2,
+			   BUF[pos].line,
+			   BUF[pos].file);
+	  }
+	}
+      }
+    }
+
+  }
+  emit1(F_BRANCH, lbl);
+  return lbl;
+}
+
+void low_insert_label(int lbl)
+{
+  lbl_cache[ lbl % LBLCACHESIZE ] = CURRENT_INSTR;
+  emit1(F_LABEL, lbl);
+}
+
+int ins_label(int lbl)
+{
+  if(lbl==-1) lbl=alloc_label();
+  low_insert_label(lbl);
+  return lbl;
+}
 
 void do_pop(int x)
 {
@@ -117,7 +166,7 @@ void do_cond_jump(node *n, int label, int iftrue, int flags)
     f=!!node_is_false(n);
     if(t || f)
     {
-      if(t == iftrue) do_jump(F_BRANCH, label);
+      if(t == iftrue) do_branch( label);
       return;
     }
   }
@@ -131,7 +180,7 @@ void do_cond_jump(node *n, int label, int iftrue, int flags)
       int tmp=alloc_label();
       do_cond_jump(CAR(n), tmp, !iftrue, flags | DO_POP);
       do_cond_jump(CDR(n), label, iftrue, flags);
-      emit1(F_LABEL,tmp);
+      low_insert_label(tmp);
     }else{
       do_cond_jump(CAR(n), label, iftrue, flags);
       do_cond_jump(CDR(n), label, iftrue, flags);
@@ -362,7 +411,7 @@ static int do_docode2(node *n, INT16 flags)
       tmp1=alloc_label();
       do_jump_when_zero(CAR(n), DO_NOT_WARN((INT32)tmp1));
       DO_CODE_BLOCK(CADR(n));
-      emit1(F_LABEL, DO_NOT_WARN((INT32)tmp1));
+      low_insert_label( DO_NOT_WARN((INT32)tmp1));
       current_switch_jumptable = prev_switch_jumptable;
       return 0;
     }
@@ -372,7 +421,7 @@ static int do_docode2(node *n, INT16 flags)
       tmp1=alloc_label();
       do_jump_when_non_zero(CAR(n), DO_NOT_WARN((INT32)tmp1));
       DO_CODE_BLOCK(CDDR(n));
-      emit1(F_LABEL, DO_NOT_WARN((INT32)tmp1));
+      low_insert_label( DO_NOT_WARN((INT32)tmp1));
       current_switch_jumptable = prev_switch_jumptable;
       return 0;
     }
@@ -384,8 +433,8 @@ static int do_docode2(node *n, INT16 flags)
     tmp3=emit1(F_POP_N_ELEMS,0);
 
     /* Else */
-    tmp2=do_jump(F_BRANCH,-1);
-    emit1(F_LABEL, DO_NOT_WARN((INT32)tmp1));
+    tmp2=do_branch(-1);
+    low_insert_label( DO_NOT_WARN((INT32)tmp1));
 
     bdroppings=do_docode(CDDR(n), flags);
     if(adroppings < bdroppings)
@@ -400,7 +449,7 @@ static int do_docode2(node *n, INT16 flags)
       adroppings=bdroppings;
     }
 
-    emit1(F_LABEL, DO_NOT_WARN((INT32)tmp2));
+    low_insert_label( DO_NOT_WARN((INT32)tmp2));
 
     current_switch_jumptable = prev_switch_jumptable;
     return adroppings;
@@ -552,7 +601,7 @@ static int do_docode2(node *n, INT16 flags)
     tmp1=alloc_label();
     do_cond_jump(CAR(n), DO_NOT_WARN((INT32)tmp1), n->token == F_LOR, 0);
     code_expression(CDR(n), flags, n->token == F_LOR ? "||" : "&&");
-    emit1(F_LABEL, DO_NOT_WARN((INT32)tmp1));
+    low_insert_label( DO_NOT_WARN((INT32)tmp1));
     return 1;
 
   case F_EQ:
@@ -687,11 +736,11 @@ static int do_docode2(node *n, INT16 flags)
     if(d_flag)
       emit0(F_MARK);
 #endif
-    tmp3=do_jump(F_BRANCH,-1);
+    tmp3=do_branch(-1);
     tmp1=ins_label(-1);
     DO_CODE_BLOCK(CDR(n));
     ins_label(current_continue);
-    emit1(F_LABEL, DO_NOT_WARN((INT32)tmp3));
+    low_insert_label( DO_NOT_WARN((INT32)tmp3));
     do_jump(n->token, DO_NOT_WARN((INT32)tmp1));
     ins_label(current_break);
 
@@ -729,12 +778,12 @@ static int do_docode2(node *n, INT16 flags)
     if(d_flag)
       emit0(F_MARK);
 #endif
-    tmp3=do_jump(F_BRANCH,-1);
+    tmp3=do_branch(-1);
     tmp1=ins_label(-1);
 
     DO_CODE_BLOCK(CDR(n));
     ins_label(current_continue);
-    emit1(F_LABEL, DO_NOT_WARN((INT32)tmp3));
+    low_insert_label( DO_NOT_WARN((INT32)tmp3));
     do_jump(n->token, DO_NOT_WARN((INT32)tmp1));
     ins_label(current_break);
 #ifdef PIKE_DEBUG
@@ -947,6 +996,7 @@ static int do_docode2(node *n, INT16 flags)
       jumptable[e] = DO_NOT_WARN((INT32)emit1(F_POINTER, 0));
       current_switch_jumptable[e]=-1;
     }
+    emit0(F_NOTREACHED);
 
     current_switch_jumptable[current_switch_case++]=-1;
 
@@ -1010,7 +1060,7 @@ static int do_docode2(node *n, INT16 flags)
     current_switch_values_on_stack = prev_switch_values_on_stack;
     current_switch_type = prev_switch_type;
 
-    emit1(F_LABEL, current_break);
+    low_insert_label( current_break);
 
     current_break=break_save;
 #ifdef PIKE_DEBUG
@@ -1120,7 +1170,7 @@ static int do_docode2(node *n, INT16 flags)
     {
       yyerror("Break outside loop or switch.");
     }else{
-      do_jump(F_BRANCH, current_break);
+      do_branch( current_break);
     }
     return 0;
 
@@ -1129,7 +1179,7 @@ static int do_docode2(node *n, INT16 flags)
     {
       yyerror("continue outside loop or switch.");
     }else{
-      do_jump(F_BRANCH, current_continue);
+      do_branch( current_continue);
     }
     return 0;
 
@@ -1375,7 +1425,7 @@ void do_code_block(node *n)
   emit1(F_BYTE,Pike_compiler->compiler_frame->max_number_of_locals);
   emit1(F_BYTE,Pike_compiler->compiler_frame->num_args);
   emit0(F_START_FUNCTION);
-  emit1(F_LABEL,0);
+  low_insert_label(0);
   if(Pike_compiler->new_program->identifier_references[Pike_compiler->compiler_frame->
 				       current_function_number].id_flags &
      ID_INLINE)
@@ -1398,11 +1448,11 @@ void do_code_block(node *n)
     Pike_compiler->compiler_frame->is_inline=1;
 
     /* This is a no-op, but prevents optimizer to delete the bytes below */
-    emit1(F_LABEL,-1);
+    low_insert_label(-1);
     emit1(F_BYTE,Pike_compiler->compiler_frame->max_number_of_locals);
     emit1(F_BYTE,Pike_compiler->compiler_frame->num_args);
     emit0(F_START_FUNCTION);
-    emit1(F_LABEL,Pike_compiler->compiler_frame->recur_label);
+    low_insert_label(Pike_compiler->compiler_frame->recur_label);
     DO_CODE_BLOCK(n);
   }
   assemble();
diff --git a/src/opcodes.h b/src/opcodes.h
index c2194f46cc..c53034c6ef 100644
--- a/src/opcodes.h
+++ b/src/opcodes.h
@@ -5,7 +5,7 @@
 \*/
 
 /*
- * $Id: opcodes.h,v 1.6 2000/05/11 14:09:46 grubba Exp $
+ * $Id: opcodes.h,v 1.7 2000/12/01 01:13:44 hubbe Exp $
  */
 #ifndef OPCODES_H
 #define OPCODES_H
@@ -233,7 +233,9 @@
 #define	F_START_FUNCTION	490
 #define	F_BYTE	491
 
-#define	F_MAX_INSTR	492
+#define F_NOTREACHED 492
+
+#define	F_MAX_INSTR	493
 
 /* Prototypes begin here */
 void index_no_free(struct svalue *to,struct svalue *what,struct svalue *ind);
diff --git a/src/peep.c b/src/peep.c
index ce6813580c..606b4112aa 100644
--- a/src/peep.c
+++ b/src/peep.c
@@ -15,18 +15,8 @@
 #include "bignum.h"
 #include "opcodes.h"
 
-RCSID("$Id: peep.c,v 1.40 2000/11/28 02:19:16 hubbe Exp $");
+RCSID("$Id: peep.c,v 1.41 2000/12/01 01:13:45 hubbe Exp $");
 
-struct p_instr_s
-{
-  short opcode;
-  short line;
-  struct pike_string *file;
-  INT32 arg;
-  INT32 arg2;
-};
-
-typedef struct p_instr_s p_instr;
 static void asm_opt(void);
 
 dynamic_buffer instrbuf;
@@ -225,6 +215,7 @@ void assemble(void)
   INT32 *labels, *jumps, *uses;
   ptrdiff_t e, length;
   p_instr *c;
+  int reoptimize=1;
 
   c=(p_instr *)instrbuf.s.str;
   length=instrbuf.s.len / sizeof(p_instr);
@@ -240,79 +231,90 @@ void assemble(void)
   jumps=(INT32 *)xalloc(sizeof(INT32) * (max_label+2));
   uses=(INT32 *)xalloc(sizeof(INT32) * (max_label+2));
 
-  for(e=0;e<=max_label;e++)
-  {
-    labels[e]=jumps[e]=-1;
-    uses[e]=0;
-  }
-
-  c=(p_instr *)instrbuf.s.str;
-  for(e=0;e<length;e++)
-    if(c[e].opcode == F_LABEL && c[e].arg>=0)
-      labels[c[e].arg]=DO_NOT_WARN((INT32)e);
-
-  for(e=0;e<length;e++)
+  while(reoptimize)
   {
-    if(instrs[c[e].opcode-F_OFFSET].flags & I_POINTER)
+    reoptimize=0;
+    for(e=0;e<=max_label;e++)
     {
-      while(1)
+      labels[e]=jumps[e]=-1;
+      uses[e]=0;
+    }
+    
+    c=(p_instr *)instrbuf.s.str;
+    for(e=0;e<length;e++)
+      if(c[e].opcode == F_LABEL && c[e].arg>=0)
+	labels[c[e].arg]=DO_NOT_WARN((INT32)e);
+    
+    for(e=0;e<length;e++)
+    {
+      if(instrs[c[e].opcode-F_OFFSET].flags & I_POINTER)
       {
-	int tmp,tmp2;
-	tmp=labels[c[e].arg];
-	
-	while(tmp<length &&
-	      (c[tmp].opcode == F_LABEL ||
-	       c[tmp].opcode == F_NOP)) tmp++;
-	
-	if(tmp>=length) break;
-
-	if(c[tmp].opcode==F_BRANCH)
+	while(1)
 	{
-	  c[e].arg=c[tmp].arg;
-	  continue;
-	}
-
+	  int tmp,tmp2;
+	  tmp=labels[c[e].arg];
+	  
+	  while(tmp<length &&
+		(c[tmp].opcode == F_LABEL ||
+		 c[tmp].opcode == F_NOP)) tmp++;
+	  
+	  if(tmp>=length) break;
+	  
+	  if(c[tmp].opcode==F_BRANCH)
+	  {
+	    c[e].arg=c[tmp].arg;
+	    continue;
+	  }
+	  
 #define TWOO(X,Y) (((X)<<8)+(Y))
-
-	switch(TWOO(c[e].opcode,c[tmp].opcode))
-	{
-	case TWOO(F_LOR,F_BRANCH_WHEN_NON_ZERO):
-	  c[e].opcode=F_BRANCH_WHEN_NON_ZERO;
-	case TWOO(F_LOR,F_LOR):
-	  c[e].arg=c[tmp].arg;
-	continue;
-	
-	case TWOO(F_LAND,F_BRANCH_WHEN_ZERO):
-	  c[e].opcode=F_BRANCH_WHEN_ZERO;
-	case TWOO(F_LAND,F_LAND):
-	  c[e].arg=c[tmp].arg;
-	continue;
-
-        case TWOO(F_LOR, F_RETURN):
-	  c[e].opcode=F_RETURN_IF_TRUE;
-	  break;
-
-        case TWOO(F_BRANCH, F_RETURN):
-        case TWOO(F_BRANCH, F_RETURN_0):
-        case TWOO(F_BRANCH, F_RETURN_1):
-        case TWOO(F_BRANCH, F_RETURN_LOCAL):
-	  if(c[e].file) free_string(c[e].file);
-	  c[e]=c[tmp];
-	  if(c[e].file) add_ref(c[e].file);
+	  
+	  switch(TWOO(c[e].opcode,c[tmp].opcode))
+	  {
+	    case TWOO(F_LOR,F_BRANCH_WHEN_NON_ZERO):
+	      c[e].opcode=F_BRANCH_WHEN_NON_ZERO;
+	    case TWOO(F_LOR,F_LOR):
+	      c[e].arg=c[tmp].arg;
+	      continue;
+	      
+	    case TWOO(F_LAND,F_BRANCH_WHEN_ZERO):
+	      c[e].opcode=F_BRANCH_WHEN_ZERO;
+	    case TWOO(F_LAND,F_LAND):
+	      c[e].arg=c[tmp].arg;
+	      continue;
+	      
+	    case TWOO(F_LOR, F_RETURN):
+	      c[e].opcode=F_RETURN_IF_TRUE;
+	      break;
+	      
+	    case TWOO(F_BRANCH, F_RETURN):
+	    case TWOO(F_BRANCH, F_RETURN_0):
+	    case TWOO(F_BRANCH, F_RETURN_1):
+	    case TWOO(F_BRANCH, F_RETURN_LOCAL):
+	      if(c[e].file) free_string(c[e].file);
+	      c[e]=c[tmp];
+	      if(c[e].file) add_ref(c[e].file);
+	      break;
+	  }
 	  break;
 	}
-	break;
+	uses[c[e].arg]++;
       }
-      uses[c[e].arg]++;
     }
+    
+    for(e=0;e<=max_label;e++)
+    {
+      if(!uses[e] && labels[e]>=0)
+      {
+	c[labels[e]].opcode=F_NOP;
+	reoptimize++;
+      }
+    }
+    if(!reoptimize) break;
+    
+    asm_opt();
+    reoptimize=0;
   }
 
-  for(e=0;e<=max_label;e++)
-    if(!uses[e] && labels[e]>=0)
-      c[labels[e]].opcode=F_NOP;
-
-  asm_opt();
-
   c=(p_instr *)instrbuf.s.str;
   length=instrbuf.s.len / sizeof(p_instr);
 
@@ -337,6 +339,7 @@ void assemble(void)
     switch(c->opcode)
     {
     case F_NOP:
+    case F_NOTREACHED:
     case F_START_FUNCTION:
       break;
     case F_ALIGN:
diff --git a/src/peep.h b/src/peep.h
index 979f90cec6..ef9715ef0d 100644
--- a/src/peep.h
+++ b/src/peep.h
@@ -1,5 +1,5 @@
 /*
- * $Id: peep.h,v 1.6 2000/08/14 17:18:06 grubba Exp $
+ * $Id: peep.h,v 1.7 2000/12/01 01:13:46 hubbe Exp $
  */
 #ifndef PEEP_H
 #define PEEP_H
@@ -7,8 +7,18 @@
 #include "dynamic_buffer.h"
 extern dynamic_buffer instrbuf;
 
+struct p_instr_s
+{
+  short opcode;
+  short line;
+  struct pike_string *file;
+  INT32 arg;
+  INT32 arg2;
+};
+
+typedef struct p_instr_s p_instr;
+
 /* Prototypes begin here */
-struct p_instr_s;
 void init_bytecode(void);
 void exit_bytecode(void);
 ptrdiff_t insert_opcode2(unsigned int f,
diff --git a/src/peep.in b/src/peep.in
index 15e2978783..2cc10eb315 100644
--- a/src/peep.in
+++ b/src/peep.in
@@ -1,5 +1,5 @@
 //
-// $Id: peep.in,v 1.41 2000/10/09 23:59:20 hubbe Exp $
+// $Id: peep.in,v 1.42 2000/12/01 01:13:46 hubbe Exp $
 //
 
 NOP :
@@ -75,6 +75,7 @@ POP_N_ELEMS RETURN_0: RETURN_0
 POP_VALUE RETURN_1: RETURN_1
 POP_N_ELEMS RETURN_1: RETURN_1
 
+NOTREACHED !LABEL : NOTREACHED
 BRANCH !LABEL : BRANCH($1a)
 RETURN !LABEL : RETURN
 RETURN_0 !LABEL : RETURN_0
@@ -246,8 +247,14 @@ BRANCH_IF_NOT_LOCAL_ARROW POINTER LABEL ($2a) : LABEL($2a)
 BRANCH_IF_LOCAL POINTER LABEL($2a) : LABEL($2a)
 BRANCH_IF_NOT_LOCAL POINTER LABEL($2a) : LABEL($2a)
 
-DEC_LOCAL_AND_POP LOCAL ($1a) : DEC_LOCAL ($1a)
-INC_LOCAL_AND_POP LOCAL ($1a) : INC_LOCAL ($1a)
+#define OPT_INCDEC(X) \
+X##_LOCAL_AND_POP LOCAL ($1a) : X##_LOCAL ($1a) ; \
+X##_LOCAL_AND_POP LOCAL LOCAL ($1a) : LOCAL($2a) X##_LOCAL ($1a) ; \
+X##_LOCAL_AND_POP GLOBAL LOCAL ($1a) : GLOBAL($2a) X##_LOCAL ($1a) ;
+
+OPT_INCDEC(INC)
+OPT_INCDEC(DEC)
+
 ASSIGN_LOCAL_AND_POP LOCAL($1a) : ASSIGN_LOCAL($1a)
 ASSIGN_GLOBAL_AND_POP GLOBAL($1a) : ASSIGN_GLOBAL($1a)
 APPLY_ASSIGN_LOCAL_AND_POP LOCAL ($1b) : APPLY_ASSIGN_LOCAL($1a,$1b)
-- 
GitLab