Checkpoint: implementing true CAL/RET instructions for subroutine calls.
authorBrian <brian@yutani.localnet.net>
Tue, 27 Mar 2007 00:46:07 +0000 (18:46 -0600)
committerBrian <brian@yutani.localnet.net>
Tue, 27 Mar 2007 00:46:07 +0000 (18:46 -0600)
Also, found/fixed a code generation regression:  the emit_swizzle() function
was always returning NULL.  This caused emit_move() to miss its chance at peephole
optimization.

src/mesa/shader/slang/slang_codegen.c
src/mesa/shader/slang/slang_compile_operation.h
src/mesa/shader/slang/slang_emit.c
src/mesa/shader/slang/slang_ir.h

index 0ca5054..93b6d9f 100644 (file)
@@ -468,6 +468,21 @@ new_float_literal(const float v[4], GLuint size)
    return n;
 }
 
+
+/**
+ * Inlined subroutine.
+ */
+static slang_ir_node *
+new_inlined_function_call(slang_ir_node *code, slang_label *name)
+{
+   slang_ir_node *n = new_node1(IR_FUNC, code);
+   assert(name);
+   if (n)
+      n->Label = name;
+   return n;
+}
+
+
 /**
  * Unconditional jump.
  */
@@ -1092,8 +1107,18 @@ _slang_gen_function_call(slang_assemble_ctx *A, slang_function *fun,
    else {
       /* non-assembly function */
       inlined = slang_inline_function_call(A, fun, oper, dest);
+      if (inlined) {
+         assert(inlined->type == SLANG_OPER_BLOCK_NEW_SCOPE ||
+                inlined->type == SLANG_OPER_SEQUENCE);
+         inlined->type = SLANG_OPER_INLINED_CALL;
+         inlined->fun = fun;
+         inlined->label = _slang_label_new((char*) fun->header.a_name);
+      }
    }
 
+   if (!inlined)
+      return NULL;
+
    /* Replace the function call with the inlined block */
    slang_operation_destruct(oper);
    *oper = *inlined;
@@ -2581,6 +2606,7 @@ _slang_gen_operation(slang_assemble_ctx * A, slang_operation *oper)
         return n;
       }
 
+   case SLANG_OPER_INLINED_CALL:
    case SLANG_OPER_SEQUENCE:
       {
          slang_ir_node *tree = NULL;
@@ -2589,6 +2615,9 @@ _slang_gen_operation(slang_assemble_ctx * A, slang_operation *oper)
             slang_ir_node *n = _slang_gen_operation(A, &oper->children[i]);
             tree = tree ? new_seq(tree, n) : n;
          }
+         if (oper->type == SLANG_OPER_INLINED_CALL) {
+            tree = new_inlined_function_call(tree, oper->label);
+         }
          return tree;
       }
 
index b63db04..d497b6f 100644 (file)
@@ -93,6 +93,7 @@ typedef enum slang_operation_type_
    SLANG_OPER_NOT,              /* "!" [expr] */
    SLANG_OPER_SUBSCRIPT,        /* [expr] "[" [expr] "]" */
    SLANG_OPER_CALL,             /* [func name] [param] [param] [...] */
+   SLANG_OPER_INLINED_CALL,     /* inlined function call */
    SLANG_OPER_FIELD,            /* i.e.: ".next" or ".xzy" or ".xxx" etc */
    SLANG_OPER_POSTINCREMENT,    /* [var] "++" */
    SLANG_OPER_POSTDECREMENT     /* [var] "--" */
index e747a6e..21b73c2 100644 (file)
@@ -62,6 +62,7 @@ typedef struct
    /* code-gen options */
    GLboolean EmitHighLevelInstructions;
    GLboolean EmitCondCodes;
+   GLboolean EmitBeginEndSub;
    GLboolean EmitComments;
 } slang_emit_info;
 
@@ -203,6 +204,13 @@ new_instruction(slang_emit_info *emitInfo, gl_inst_opcode opcode)
 {
    struct gl_program *prog = emitInfo->prog;
    struct prog_instruction *inst;
+
+#if 0
+   /* print prev inst */
+   if (prog->NumInstructions > 0) {
+      _mesa_print_instruction(prog->Instructions + prog->NumInstructions - 1);
+   }
+#endif
    prog->Instructions = _mesa_realloc_instructions(prog->Instructions,
                                                    prog->NumInstructions,
                                                    prog->NumInstructions + 1);
@@ -710,6 +718,28 @@ emit_label(slang_emit_info *emitInfo, const slang_ir_node *n)
 }
 
 
+/**
+ * Emit code for an inlined function call.
+ */
+static struct prog_instruction *
+emit_func(slang_emit_info *emitInfo, slang_ir_node *n)
+{
+   struct prog_instruction *inst;
+   assert(n->Label);
+   if (emitInfo->EmitBeginEndSub) {
+      inst = new_instruction(emitInfo, OPCODE_BGNSUB);
+      inst->Comment = _mesa_strdup(n->Label->Name);
+   }
+   inst = emit(emitInfo, n->Children[0]);
+   if (emitInfo->EmitBeginEndSub) {
+      inst = new_instruction(emitInfo, OPCODE_ENDSUB);
+      inst->Comment = _mesa_strdup(n->Label->Name);
+   }
+   n->Store = n->Children[0]->Store;
+   return inst;
+}
+
+
 static struct prog_instruction *
 emit_return(slang_emit_info *emitInfo, slang_ir_node *n)
 {
@@ -803,14 +833,20 @@ emit_move(slang_emit_info *emitInfo, slang_ir_node *n)
    n->Store = n->Children[0]->Store;
 
 #if PEEPHOLE_OPTIMIZATIONS
-   if (inst && _slang_is_temp(emitInfo->vt, n->Children[1]->Store)) {
+   if (inst &&
+       _slang_is_temp(emitInfo->vt, n->Children[1]->Store) &&
+       (inst->DstReg.File == n->Children[1]->Store->File) &&
+       (inst->DstReg.Index == n->Children[1]->Store->Index)) {
       /* Peephole optimization:
-       * Just modify the RHS to put its result into the dest of this
-       * MOVE operation.  Then, this MOVE is a no-op.
+       * The Right-Hand-Side has its results in a temporary place.
+       * Modify the RHS (and the prev instruction) to store its results
+       * in the destination specified by n->Children[0].
+       * Then, this MOVE is a no-op.
        */
-      _slang_free_temp(emitInfo->vt, n->Children[1]->Store);
+      if (n->Children[1]->Opcode != IR_SWIZZLE)
+         _slang_free_temp(emitInfo->vt, n->Children[1]->Store);
       *n->Children[1]->Store = *n->Children[0]->Store;
-      /* fixup the prev (RHS) instruction */
+      /* fixup the previous instruction (which stored the RHS result) */
       assert(n->Children[0]->Store->Index >= 0);
       storage_to_dst_reg(&inst->DstReg, n->Children[0]->Store, n->Writemask);
       return inst;
@@ -870,11 +906,17 @@ emit_cond(slang_emit_info *emitInfo, slang_ir_node *n)
        * Need to update condition code register.
        * Next instruction is typically an IR_IF.
        */
-      if (inst) {
-         /* set inst's CondUpdate flag */
+      if (inst &&
+          n->Children[0]->Store &&
+          inst->DstReg.File == n->Children[0]->Store->File &&
+          inst->DstReg.Index == n->Children[0]->Store->Index) {
+         /* The previous instruction wrote to the register who's value
+          * we're testing.  Just update that instruction so that the
+          * condition codes are updated.
+          */
          inst->CondUpdate = GL_TRUE;
          n->Store = n->Children[0]->Store;
-         return inst; /* XXX or null? */
+         return inst;
       }
       else {
          /* This'll happen for things like "if (i) ..." where no code
@@ -1227,8 +1269,9 @@ static struct prog_instruction *
 emit_swizzle(slang_emit_info *emitInfo, slang_ir_node *n)
 {
    GLuint swizzle;
+   struct prog_instruction *inst;
 
-   (void) emit(emitInfo, n->Children[0]);
+   inst = emit(emitInfo, n->Children[0]);
 
 #ifdef DEBUG
    {
@@ -1246,10 +1289,10 @@ emit_swizzle(slang_emit_info *emitInfo, slang_ir_node *n)
    n->Store->Index = n->Children[0]->Store->Index;
    n->Store->Size = swizzle_size(n->Store->Swizzle);
 #if 0
-   printf("Emit Swizzle reg %d  chSize %d  size %d  swz %s\n",
+   printf("Emit Swizzle %s  reg %d  chSize %d  mySize %d\n",
+          _mesa_swizzle_string(n->Store->Swizzle, 0, 0),
           n->Store->Index, n->Children[0]->Store->Size,
-          n->Store->Size,
-          _mesa_swizzle_string(n->Store->Swizzle, 0, 0));
+          n->Store->Size);
 #endif
 
    /* apply this swizzle to child's swizzle to get composed swizzle */
@@ -1257,7 +1300,7 @@ emit_swizzle(slang_emit_info *emitInfo, slang_ir_node *n)
    n->Store->Swizzle = swizzle_swizzle(n->Children[0]->Store->Swizzle,
                                        swizzle);
 
-   return NULL;
+   return inst;
 }
 
 
@@ -1505,6 +1548,9 @@ emit(slang_emit_info *emitInfo, slang_ir_node *n)
    case IR_KILL:
       return emit_kill(emitInfo);
 
+   case IR_FUNC:
+      return emit_func(emitInfo, n);
+
    case IR_IF:
       return emit_if(emitInfo, n);
 
@@ -1553,6 +1599,7 @@ _slang_emit_code(slang_ir_node *n, slang_var_table *vt,
 
    emitInfo.EmitHighLevelInstructions = ctx->Shader.EmitHighLevelInstructions;
    emitInfo.EmitCondCodes = ctx->Shader.EmitCondCodes;
+   emitInfo.EmitBeginEndSub = 0;  /* XXX temporary */
    emitInfo.EmitComments = ctx->Shader.EmitComments;
 
    (void) emit(&emitInfo, n);
index a617a7e..a9a530a 100644 (file)
@@ -62,6 +62,8 @@ typedef enum
    IR_RETURN,    /* return from subroutine */
    IR_CALL,      /* call subroutine */
 
+   IR_FUNC,      /* inlined function code */
+
    IR_LOOP,      /* high-level loop-begin / loop-end */
                  /* Children[0] = loop body */
                  /* Children[1] = loop tail code, or NULL */