From 9878e8ff516486900228429f26b37cb01cd7313f Mon Sep 17 00:00:00 2001 From: Brian Date: Mon, 26 Mar 2007 18:46:07 -0600 Subject: [PATCH] Checkpoint: implementing true CAL/RET instructions for subroutine calls. 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 | 29 ++++++++++ src/mesa/shader/slang/slang_compile_operation.h | 1 + src/mesa/shader/slang/slang_emit.c | 73 ++++++++++++++++++++----- src/mesa/shader/slang/slang_ir.h | 2 + 4 files changed, 92 insertions(+), 13 deletions(-) diff --git a/src/mesa/shader/slang/slang_codegen.c b/src/mesa/shader/slang/slang_codegen.c index 0ca5054eadc..93b6d9f8544 100644 --- a/src/mesa/shader/slang/slang_codegen.c +++ b/src/mesa/shader/slang/slang_codegen.c @@ -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; } diff --git a/src/mesa/shader/slang/slang_compile_operation.h b/src/mesa/shader/slang/slang_compile_operation.h index b63db04e7eb..d497b6f66f7 100644 --- a/src/mesa/shader/slang/slang_compile_operation.h +++ b/src/mesa/shader/slang/slang_compile_operation.h @@ -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] "--" */ diff --git a/src/mesa/shader/slang/slang_emit.c b/src/mesa/shader/slang/slang_emit.c index e747a6ef327..21b73c2f971 100644 --- a/src/mesa/shader/slang/slang_emit.c +++ b/src/mesa/shader/slang/slang_emit.c @@ -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); diff --git a/src/mesa/shader/slang/slang_ir.h b/src/mesa/shader/slang/slang_ir.h index a617a7e1737..a9a530aaf8f 100644 --- a/src/mesa/shader/slang/slang_ir.h +++ b/src/mesa/shader/slang/slang_ir.h @@ -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 */ -- 2.11.0