diff options
| author | Brian <brian@yutani.localnet.net> | 2007-03-27 16:04:36 -0600 | 
|---|---|---|
| committer | Brian <brian@yutani.localnet.net> | 2007-03-27 16:06:48 -0600 | 
| commit | e5d00e8cf4659f03fe3061326a24b6a670f7c8f2 (patch) | |
| tree | 448035a18748294c6873d4a67dd35857aa6cb0ed /src | |
| parent | 31dc7a3c890a831f9a0d20dc394ddbe854a05718 (diff) | |
Implement true CAL/RET subroutines. Some optimizations, clean-ups coming...
Diffstat (limited to 'src')
| -rw-r--r-- | src/mesa/shader/slang/slang_codegen.c | 10 | ||||
| -rw-r--r-- | src/mesa/shader/slang/slang_emit.c | 171 | 
2 files changed, 162 insertions, 19 deletions
| diff --git a/src/mesa/shader/slang/slang_codegen.c b/src/mesa/shader/slang/slang_codegen.c index 93b6d9f854..cf3569c3b0 100644 --- a/src/mesa/shader/slang/slang_codegen.c +++ b/src/mesa/shader/slang/slang_codegen.c @@ -1107,12 +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) { +      if (inlined && _slang_find_node_type(inlined, SLANG_OPER_RETURN)) { +         /* This inlined function has one or more 'return' statements. +          * So, we can't truly inline this function because we need to +          * implement 'return' with RET (and CAL). +          * XXX check if there's one 'return' and if it's the very last +          * statement in the function - we can optimize that case. +          */           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); +         inlined->label = _slang_label_new_unique((char*) fun->header.a_name);        }     } diff --git a/src/mesa/shader/slang/slang_emit.c b/src/mesa/shader/slang/slang_emit.c index 21b73c2f97..64163c4959 100644 --- a/src/mesa/shader/slang/slang_emit.c +++ b/src/mesa/shader/slang/slang_emit.c @@ -51,23 +51,42 @@  #define ANNOTATE 0 -/* XXX temporarily here */ - -  typedef struct  {     slang_info_log *log;     slang_var_table *vt;     struct gl_program *prog; +   struct gl_program **Subroutines; +   GLuint NumSubroutines; +     /* code-gen options */     GLboolean EmitHighLevelInstructions;     GLboolean EmitCondCodes; -   GLboolean EmitBeginEndSub;     GLboolean EmitComments; +   GLboolean EmitBeginEndSub; /* XXX TEMPORARY */  } slang_emit_info; +static struct gl_program * +new_subroutine(slang_emit_info *emitInfo, GLuint *id) +{ +   GET_CURRENT_CONTEXT(ctx); +   const GLuint n = emitInfo->NumSubroutines; + +   emitInfo->Subroutines = (struct gl_program **) +      _mesa_realloc(emitInfo->Subroutines, +                    n * sizeof(struct gl_program), +                    (n + 1) * sizeof(struct gl_program)); +   emitInfo->Subroutines[n] = _mesa_new_program(ctx, emitInfo->prog->Target, 0); +   emitInfo->Subroutines[n]->Parameters = emitInfo->prog->Parameters; +   emitInfo->NumSubroutines++; +   *id = n; +   return emitInfo->Subroutines[n]; +} + + +  /**   * Swizzle a swizzle.  That is, return swz2(swz1)   */ @@ -227,19 +246,18 @@ new_instruction(slang_emit_info *emitInfo, gl_inst_opcode opcode)  } -#if 0  /**   * Return pointer to last instruction in program.   */  static struct prog_instruction * -prev_instruction(struct gl_program *prog) +prev_instruction(slang_emit_info *emitInfo)  { +   struct gl_program *prog = emitInfo->prog;     if (prog->NumInstructions == 0)        return NULL;     else        return prog->Instructions + prog->NumInstructions - 1;  } -#endif  static struct prog_instruction * @@ -719,27 +737,62 @@ emit_label(slang_emit_info *emitInfo, const slang_ir_node *n)  /** - * Emit code for an inlined function call. + * Emit code for an inlined function call (subroutine).   */  static struct prog_instruction *  emit_func(slang_emit_info *emitInfo, slang_ir_node *n)  { +   struct gl_program *progSave;     struct prog_instruction *inst; +   GLuint subroutineId; + +   assert(n->Opcode == IR_FUNC);     assert(n->Label); + +   /* save/push cur program */ +   progSave = emitInfo->prog; +   emitInfo->prog = new_subroutine(emitInfo, &subroutineId); + +   _slang_label_set_location(n->Label, emitInfo->prog->NumInstructions, +                             emitInfo->prog); +     if (emitInfo->EmitBeginEndSub) {        inst = new_instruction(emitInfo, OPCODE_BGNSUB);        inst->Comment = _mesa_strdup(n->Label->Name);     } -   inst = emit(emitInfo, n->Children[0]); + +   /* body of function: */ +   emit(emitInfo, n->Children[0]); +   n->Store = n->Children[0]->Store; + +   /* add RET instruction now, if needed */ +   inst = prev_instruction(emitInfo); +   if (inst && inst->Opcode != OPCODE_RET) { +      inst = new_instruction(emitInfo, OPCODE_RET); +   } +     if (emitInfo->EmitBeginEndSub) {        inst = new_instruction(emitInfo, OPCODE_ENDSUB);        inst->Comment = _mesa_strdup(n->Label->Name);     } -   n->Store = n->Children[0]->Store; + +   /* pop/restore cur program */ +   emitInfo->prog = progSave; + +   /* emit the function call */ +   inst = new_instruction(emitInfo, OPCODE_CAL); +   /* The branch target is just the subroutine number (changed later) */ +   inst->BranchTarget = subroutineId; +   inst->Comment = _mesa_strdup(n->Label->Name); +   assert(inst->BranchTarget >= 0); +     return inst;  } +/** + * Emit code for a 'return' statement. + */  static struct prog_instruction *  emit_return(slang_emit_info *emitInfo, slang_ir_node *n)  { @@ -747,12 +800,17 @@ emit_return(slang_emit_info *emitInfo, slang_ir_node *n)     assert(n);     assert(n->Opcode == IR_RETURN);     assert(n->Label); -   inst = new_instruction(emitInfo, OPCODE_BRA /*RET*/); /*XXX TEMPORARY*/ -   inst->DstReg.CondMask = COND_TR;  /* always branch */ -   inst->BranchTarget = _slang_label_get_location(n->Label); -   if (inst->BranchTarget < 0) { -      _slang_label_add_reference(n->Label, emitInfo->prog->NumInstructions - 1); +   inst = new_instruction(emitInfo, OPCODE_RET/*BRA*/); /*XXX TEMPORARY*/ +   inst->DstReg.CondMask = COND_TR;  /* always return/branch */ + +   if (inst->Opcode == OPCODE_BRA) { +      inst->BranchTarget = _slang_label_get_location(n->Label); +      if (inst->BranchTarget < 0) { +         _slang_label_add_reference(n->Label, +                                    emitInfo->prog->NumInstructions - 1); +      }     } +     return inst;  } @@ -1549,7 +1607,11 @@ emit(slang_emit_info *emitInfo, slang_ir_node *n)        return emit_kill(emitInfo);     case IR_FUNC: -      return emit_func(emitInfo, n); +      /* new variable scope for subroutines/function calls*/ +      _slang_push_var_table(emitInfo->vt); +      inst = emit_func(emitInfo, n); +      _slang_pop_var_table(emitInfo->vt); +      return inst;     case IR_IF:        return emit_if(emitInfo, n); @@ -1584,6 +1646,76 @@ emit(slang_emit_info *emitInfo, slang_ir_node *n)  } +/** + * After code generation, any subroutines will be in separate program + * objects.  This function appends all the subroutines onto the main + * program and resolves the linking of all the branch/call instructions. + * XXX this logic should really be part of the linking process... + */ +static void +_slang_resolve_subroutines(slang_emit_info *emitInfo) +{ +   GET_CURRENT_CONTEXT(ctx); +   struct gl_program *mainP = emitInfo->prog; +   GLuint *subroutineLoc, i, total; + +   subroutineLoc +      = (GLuint *) _mesa_malloc(emitInfo->NumSubroutines * sizeof(GLuint)); + +   /* total number of instructions */ +   total = mainP->NumInstructions; +   for (i = 0; i < emitInfo->NumSubroutines; i++) { +      subroutineLoc[i] = total; +      total += emitInfo->Subroutines[i]->NumInstructions; +   } + +   /* adjust BrancTargets within the functions */ +   for (i = 0; i < emitInfo->NumSubroutines; i++) { +      struct gl_program *sub = emitInfo->Subroutines[i]; +      GLuint j; +      for (j = 0; j < sub->NumInstructions; j++) { +         struct prog_instruction *inst = sub->Instructions + j; +         if (inst->Opcode != OPCODE_CAL && inst->BranchTarget >= 0) { +            inst->BranchTarget += subroutineLoc[i]; +         } +      } +   } + +   /* append subroutines' instructions after main's instructions */ +   mainP->Instructions = _mesa_realloc_instructions(mainP->Instructions, +                                                    mainP->NumInstructions, +                                                    total); +   for (i = 0; i < emitInfo->NumSubroutines; i++) { +      struct gl_program *sub = emitInfo->Subroutines[i]; +      _mesa_copy_instructions(mainP->Instructions + subroutineLoc[i], +                              sub->Instructions, +                              sub->NumInstructions); +      /* delete subroutine code */ +      sub->Parameters = NULL; /* prevent double-free */ +      _mesa_delete_program(ctx, sub); +   } +   mainP->NumInstructions = total; + +   /* Examine CAL instructions. +    * At this point, the BranchTarget field of the CAL instructions is +    * the number/id of the subroutine to call (an index into the +    * emitInfo->Subroutines list). +    * Translate that into an actual instruction location now. +    */ +   for (i = 0; i < mainP->NumInstructions; i++) { +      struct prog_instruction *inst = mainP->Instructions + i; +      if (inst->Opcode == OPCODE_CAL) { +         const GLuint f = inst->BranchTarget; +         inst->BranchTarget = subroutineLoc[f]; +      } +   } + +   _mesa_free(subroutineLoc); +} + + + +  GLboolean  _slang_emit_code(slang_ir_node *n, slang_var_table *vt,                   struct gl_program *prog, GLboolean withEnd, @@ -1596,11 +1728,13 @@ _slang_emit_code(slang_ir_node *n, slang_var_table *vt,     emitInfo.log = log;     emitInfo.vt = vt;     emitInfo.prog = prog; +   emitInfo.Subroutines = NULL; +   emitInfo.NumSubroutines = 0;     emitInfo.EmitHighLevelInstructions = ctx->Shader.EmitHighLevelInstructions;     emitInfo.EmitCondCodes = ctx->Shader.EmitCondCodes; -   emitInfo.EmitBeginEndSub = 0;  /* XXX temporary */     emitInfo.EmitComments = ctx->Shader.EmitComments; +   emitInfo.EmitBeginEndSub = 0;  /* XXX for compiler debug only */     (void) emit(&emitInfo, n); @@ -1609,6 +1743,9 @@ _slang_emit_code(slang_ir_node *n, slang_var_table *vt,        struct prog_instruction *inst;        inst = new_instruction(&emitInfo, OPCODE_END);     } + +   _slang_resolve_subroutines(&emitInfo); +     success = GL_TRUE;  #if 0 | 
