Leopold Toetsch wrote:

2. Proposal for _keyed opcodes
------------------------------

The thread with subject "pdd06_pasm, pdd08_keys: _keyed ops" clearly
showes the shortcomings of the current _keyed opcodes and the
implementation of these.[1]

The 3 operand keyed add @a[$i] = @b[3] + %h{"k"}:

    add_p_ki_p_kic_p_kc

Attached is a proof of concept of my proposal.

A 6 operand 3 keyed op get's rewritten like so:

/* OP _p_k _p_k_p_k =>
* set py, p_k
* set pz, p_k
* new px, .PerlUndef
* OP px, py, pz
* set _p_k_px
*/

- It uses only set_ ops
- only imcc, but with pasm syntax in example

With an approach like this, we could cut down the VTABLE to roughly 1/3 of it's current size. The _keyed entrys would only consist of the set_.._keyed{,_int} variants plus exists_keyed and defined_keyed. And, we would never have the opcode explosion to 64 times of current size.

Attached is
- patch to imcc.y
- 3key.imc (example)
- a.pasm (output for above)

$ parrot a.pbc
300
leo
--- parrot/languages/imcc/imcc.y        Mon Oct 21 13:56:24 2002
+++ parrot-leo/languages/imcc/imcc.y    Mon Oct 21 17:34:18 2002
@@ -240,6 +240,100 @@
 }
 
 
+static Instruction *
+multi_keyed(char *name, SymReg ** regs, int nr, int emit)
+{
+    int i, keys, kv, n;
+    char buf[16];
+    static int p = 0;
+    SymReg *preg[IMCC_MAX_REGS];    /* px,py,pz */
+    SymReg *nreg[IMCC_MAX_REGS];
+    Instruction * ins, *last;
+
+    /* count keys in keyvec */
+    kv = keyvec;
+    for (i = keys = 0; i < nr; i++, kv >>= 1)
+        if (kv & 1)
+            keys++;
+    if (keys <= 1)
+        return 0;
+    /* XXX what to do, if we don't emit instruction? */
+    assert(emit);
+    /* OP  _p_k    _p_k_p_k =>
+     * set      py, p_k
+     * set      pz,     p_k
+     * new px, .PerlUndef
+     * OP  px, py, pz
+     * set _p_k_px
+     */
+
+    kv = keyvec;
+    for (i = n = 0; i < nr; i++, kv >>= 1, n++) {
+        if (kv & 1) {
+            fataly(EX_SOFTWARE, "multi_keyed", line,"illegal key operand\n");
+        }
+        /* make a new P symbol */
+        while (1) {
+            sprintf(buf, "$P%d", ++p);
+            if (get_sym(buf) == 0)
+                break;
+        }
+        preg[n] = mk_symreg(buf, 'P');
+        kv >>= 1;
+        if (kv & 1) {
+            /* we have a keyed operand */
+            if (regs[i]->set != 'P') {
+                fataly(EX_SOFTWARE, "multi_keyed", line,"not an aggregate\n");
+            }
+            nargs = 3;
+            /* don't emit LHS yet */
+            if (i == 0) {
+                keyvec = 1 << 1;
+                nreg[0] = regs[i];
+                nreg[1] = regs[i+1];
+                nreg[2] = preg[n];
+                /* set p_k px */
+                ins = iANY(str_dup("set"), 0, nreg, 0);
+            }
+            else {
+                keyvec = 1 << 2;
+                nreg[0] = preg[n];
+                nreg[1] = regs[i];
+                nreg[2] = regs[i+1];
+                /* set py|z p_k */
+                iANY(str_dup("set"), 0, nreg, 1);
+            }
+            i++;
+        }
+        /* non keyed */
+        else {
+            nargs = 2;
+            keyvec = 0;
+            if (i == 0) {
+                nreg[0] = regs[i];
+                nreg[1] = preg[n];
+                /* set n, px */
+                ins = iANY(str_dup("set"), 0, nreg, 0);
+            }
+            else {
+                nreg[0] = preg[n];
+                nreg[1] = regs[i];
+                /* set px, n */
+                iANY(str_dup("set"), 0, nreg, 1);
+            }
+        }
+    }
+    /* make a new undef */
+    iNEW(preg[0], str_dup("PerlUndef"), 1);
+    /* emit the operand */
+    nargs = 3;
+    keyvec = 0;
+    iANY(name, 0, preg, 1);
+    /* emit the LHS op */
+    emitb(ins);
+    return ins;
+}
+
 Instruction * iANY(char * name, char *fmt, SymReg **regs, int emit) {
     char fullname[64];
     int i;
@@ -247,6 +341,10 @@
     int op;
     Instruction * ins;
 
+    ins = multi_keyed(name, regs, nargs, emit);
+    if (ins)
+        return ins;
+
     op_fullname(fullname, name, regs, nargs);
     op = interpreter->op_lib->op_code(fullname, 1);
     if (op >= 0) {
@@ -332,7 +430,6 @@
         fataly(EX_SOFTWARE, "iANY", line,"op not found '%s' (%s<%d>)\n",
                 fullname, name, nargs);
     }
-    clear_state();
     return ins;
 }
 
@@ -384,7 +481,8 @@
 
 pasmline: labels  pasm_inst '\n'  { $$ = 0; }
     ;
-pasm_inst: PARROT_OP pasm_args         { $$ = iANY($1,0,regs,1); free($1); }
+pasm_inst: {clear_state();}
+       PARROT_OP pasm_args             { $$ = iANY($2,0,regs,1); free($2); }
     | /* none */                               { $$ = 0;}
 
     ;
@@ -427,7 +525,8 @@
     |   statements statement
     ;
 
-statement:  instruction
+statement:  {clear_state(); }
+        instruction
     ;
 
 labels:        /* none */         { $$ = NULL; }
--- parrot/3key.imc     Mon Oct 21 17:34:24 2002
+++ parrot-leo/3key.imc Mon Oct 21 15:57:17 2002
@@ -0,0 +1,14 @@
+.sub _main
+       P0 = new PerlArray
+       P1 = new PerlArray
+       P2 = new PerlArray
+       set P1[0], 100
+       set P2[1], 200
+       set I2, 1
+       add P0[2], P1[0], P2[I2]
+       set I0, P0[2]
+       print I0
+       print "\n"
+       end
+ret
+
--- parrot/a.pasm       Mon Oct 21 17:34:24 2002
+++ parrot-leo/a.pasm   Mon Oct 21 17:14:05 2002
@@ -0,0 +1,19 @@
+_main:
+       new P0, 10       # .PerlArray
+       new P1, 10       # .PerlArray
+       new P2, 10       # .PerlArray
+       set P1[0], 100
+       set P2[1], 200
+       set I2, 1
+       set P4, P1[0]
+       set P3, P2[I2]
+       new P1, 15       # .PerlUndef
+       add P1, P4, P3
+       set P0[2], P1
+       set I0, P0[2]
+       print I0
+       print "\n"
+       end 
+       ret 
+
+

Reply via email to