mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-05-04 20:38:06 +02:00
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.
This commit is contained in:
parent
6583429f89
commit
9878e8ff51
4 changed files with 92 additions and 13 deletions
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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] "--" */
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue