i965: rewrite the code for handling shader subroutine calls

Previously, the prog_instruction::Data field was used to map original Mesa
instructions to brw instructions in order to resolve subroutine calls.  This
was a rather tangled mess.  Plus it's an obstacle to implementing dynamic
allocation/growing of the instruction buffer (it's still a fixed size).

Mesa's GLSL compiler emits a label for each subroutine and CAL instruction.
Now we use those labels to patch the subroutine calls after code generation
has been done.  We just keep a list of all CAL instructions that needs patching
and a list of all subroutine labels.  It's a simple matter to resolve them.

This also consolidates some redundant post-emit code between brw_vs_emit.c and
brw_wm_glsl.c and removes some loops that cleared the prog_instruction::Data
fields at the end.

Plus, a bunch of new comments.
This commit is contained in:
Brian Paul 2009-02-13 17:17:52 -07:00
parent 74b6d55864
commit c51c822ee0
6 changed files with 187 additions and 64 deletions

View File

@ -129,3 +129,126 @@ const GLuint *brw_get_program( struct brw_compile *p,
return (const GLuint *)p->store;
}
/**
* Subroutine calls require special attention.
* Mesa instructions may be expanded into multiple hardware instructions
* so the prog_instruction::BranchTarget field can't be used as an index
* into the hardware instructions.
*
* The BranchTarget field isn't needed, however. Mesa's GLSL compiler
* emits CAL and BGNSUB instructions with labels that can be used to map
* subroutine calls to actual subroutine code blocks.
*
* The structures and function here implement patching of CAL instructions
* so they jump to the right subroutine code...
*/
/**
* For each OPCODE_BGNSUB we create one of these.
*/
struct brw_glsl_label
{
const char *name; /**< the label string */
GLuint position; /**< the position of the brw instruction for this label */
struct brw_glsl_label *next; /**< next in linked list */
};
/**
* For each OPCODE_CAL we create one of these.
*/
struct brw_glsl_call
{
GLuint call_inst_pos; /**< location of the CAL instruction */
const char *sub_name; /**< name of subroutine to call */
struct brw_glsl_call *next; /**< next in linked list */
};
/**
* Called for each OPCODE_BGNSUB.
*/
void
brw_save_label(struct brw_compile *c, const char *name, GLuint position)
{
struct brw_glsl_label *label = CALLOC_STRUCT(brw_glsl_label);
label->name = name;
label->position = position;
label->next = c->first_label;
c->first_label = label;
}
/**
* Called for each OPCODE_CAL.
*/
void
brw_save_call(struct brw_compile *c, const char *name, GLuint call_pos)
{
struct brw_glsl_call *call = CALLOC_STRUCT(brw_glsl_call);
call->call_inst_pos = call_pos;
call->sub_name = name;
call->next = c->first_call;
c->first_call = call;
}
/**
* Lookup a label, return label's position/offset.
*/
static GLuint
brw_lookup_label(struct brw_compile *c, const char *name)
{
const struct brw_glsl_label *label;
for (label = c->first_label; label; label = label->next) {
if (strcmp(name, label->name) == 0) {
return label->position;
}
}
abort(); /* should never happen */
return ~0;
}
/**
* When we're done generating code, this function is called to resolve
* subroutine calls.
*/
void
brw_resolve_cals(struct brw_compile *c)
{
const struct brw_glsl_call *call;
for (call = c->first_call; call; call = call->next) {
const GLuint sub_loc = brw_lookup_label(c, call->sub_name);
struct brw_instruction *brw_call_inst = &c->store[call->call_inst_pos];
struct brw_instruction *brw_sub_inst = &c->store[sub_loc];
GLint offset = brw_sub_inst - brw_call_inst;
/* patch brw_inst1 to point to brw_inst2 */
brw_set_src1(brw_call_inst, brw_imm_d(offset * 16));
}
/* free linked list of calls */
{
struct brw_glsl_call *call, *next;
for (call = c->first_call; call; call = next) {
next = call->next;
_mesa_free(call);
}
c->first_call = NULL;
}
/* free linked list of labels */
{
struct brw_glsl_label *label, *next;
for (label = c->first_label; label; label = next) {
next = label->next;
_mesa_free(label);
}
c->first_label = NULL;
}
}

View File

@ -91,6 +91,11 @@ struct brw_indirect {
};
struct brw_glsl_label;
struct brw_glsl_call;
#define BRW_EU_MAX_INSN_STACK 5
#define BRW_EU_MAX_INSN 1200
@ -106,9 +111,22 @@ struct brw_compile {
GLuint flag_value;
GLboolean single_program_flow;
struct brw_context *brw;
struct brw_glsl_label *first_label; /**< linked list of labels */
struct brw_glsl_call *first_call; /**< linked list of CALs */
};
void
brw_save_label(struct brw_compile *c, const char *name, GLuint position);
void
brw_save_call(struct brw_compile *c, const char *name, GLuint call_pos);
void
brw_resolve_cals(struct brw_compile *c);
static INLINE int type_sz( GLuint type )
{

View File

@ -954,36 +954,27 @@ static void emit_vertex_write( struct brw_vs_compile *c)
}
/**
* Called after code generation to resolve subroutine calls and the
* END instruction.
* \param end_inst points to brw code for END instruction
* \param last_inst points to last instruction emitted before vertex write
*/
static void
post_vs_emit( struct brw_vs_compile *c, struct brw_instruction *end_inst )
post_vs_emit( struct brw_vs_compile *c,
struct brw_instruction *end_inst,
struct brw_instruction *last_inst )
{
GLuint nr_insns = c->vp->program.Base.NumInstructions;
GLuint insn, target_insn;
struct prog_instruction *inst1, *inst2;
struct brw_instruction *brw_inst1, *brw_inst2;
int offset;
for (insn = 0; insn < nr_insns; insn++) {
inst1 = &c->vp->program.Base.Instructions[insn];
brw_inst1 = inst1->Data;
switch (inst1->Opcode) {
case OPCODE_CAL:
case OPCODE_BRA:
target_insn = inst1->BranchTarget;
inst2 = &c->vp->program.Base.Instructions[target_insn];
brw_inst2 = inst2->Data;
offset = brw_inst2 - brw_inst1;
brw_set_src1(brw_inst1, brw_imm_d(offset*16));
break;
case OPCODE_END:
offset = end_inst - brw_inst1;
brw_set_src1(brw_inst1, brw_imm_d(offset*16));
break;
default:
break;
}
}
GLint offset;
brw_resolve_cals(&c->func);
/* patch up the END code to jump past subroutines, etc */
offset = last_inst - end_inst;
brw_set_src1(end_inst, brw_imm_d(offset * 16));
}
/* Emit the fragment program instructions here.
*/
void brw_vs_emit(struct brw_vs_compile *c )
@ -992,7 +983,8 @@ void brw_vs_emit(struct brw_vs_compile *c )
struct brw_compile *p = &c->func;
GLuint nr_insns = c->vp->program.Base.NumInstructions;
GLuint insn, if_insn = 0;
struct brw_instruction *end_inst;
GLuint end_offset = 0;
struct brw_instruction *end_inst, *last_inst;
struct brw_instruction *if_inst[MAX_IFSN];
struct brw_indirect stack_index = brw_indirect(0, 0);
@ -1035,7 +1027,6 @@ void brw_vs_emit(struct brw_vs_compile *c )
/* Get argument regs. SWZ is special and does this itself.
*/
inst->Data = &p->store[p->nr_insn];
if (inst->Opcode != OPCODE_SWZ)
for (i = 0; i < 3; i++) {
struct prog_src_register *src = &inst->SrcReg[i];
@ -1203,7 +1194,7 @@ void brw_vs_emit(struct brw_vs_compile *c )
brw_set_access_mode(p, BRW_ALIGN_16);
brw_ADD(p, get_addr_reg(stack_index),
get_addr_reg(stack_index), brw_imm_d(4));
inst->Data = &p->store[p->nr_insn];
brw_save_call(p, inst->Comment, p->nr_insn);
brw_ADD(p, brw_ip_reg(), brw_ip_reg(), brw_imm_d(1*16));
break;
case OPCODE_RET:
@ -1214,13 +1205,21 @@ void brw_vs_emit(struct brw_vs_compile *c )
brw_set_access_mode(p, BRW_ALIGN_16);
break;
case OPCODE_END:
end_offset = p->nr_insn;
/* this instruction will get patched later to jump past subroutine
* code, etc.
*/
brw_ADD(p, brw_ip_reg(), brw_ip_reg(), brw_imm_d(1*16));
break;
case OPCODE_PRINT:
/* no-op */
break;
case OPCODE_BGNSUB:
brw_save_label(p, inst->Comment, p->nr_insn);
break;
case OPCODE_ENDSUB:
/* no-op instructions */
break;
/* no-op */
break;
default:
_mesa_problem(NULL, "Unsupported opcode %i (%s) in vertex shader",
inst->Opcode, inst->Opcode < MAX_OPCODE ?
@ -1258,9 +1257,11 @@ void brw_vs_emit(struct brw_vs_compile *c )
release_tmps(c);
}
end_inst = &p->store[p->nr_insn];
end_inst = &p->store[end_offset];
last_inst = &p->store[p->nr_insn];
/* The END instruction will be patched to jump to this code */
emit_vertex_write(c);
post_vs_emit(c, end_inst);
for (insn = 0; insn < nr_insns; insn++)
c->vp->program.Base.Instructions[insn].Data = NULL;
post_vs_emit(c, end_inst, last_inst);
}

View File

@ -281,4 +281,6 @@ void brw_wm_lookup_iz( GLuint line_aa,
GLboolean brw_wm_is_glsl(const struct gl_fragment_program *fp);
void brw_wm_glsl_emit(struct brw_context *brw, struct brw_wm_compile *c);
#endif

View File

@ -183,7 +183,6 @@ static struct prog_instruction *emit_insn(struct brw_wm_compile *c,
{
struct prog_instruction *inst = get_fp_inst(c);
*inst = *inst0;
inst->Data = (void *)inst0;
return inst;
}

View File

@ -2252,28 +2252,12 @@ static void emit_tex(struct brw_wm_compile *c,
brw_MOV(p, dst[3], brw_imm_f(1.0));
}
/**
* Resolve subroutine calls after code emit is done.
*/
static void post_wm_emit( struct brw_wm_compile *c )
{
GLuint nr_insns = c->fp->program.Base.NumInstructions;
GLuint insn, target_insn;
struct prog_instruction *inst1, *inst2;
struct brw_instruction *brw_inst1, *brw_inst2;
int offset;
for (insn = 0; insn < nr_insns; insn++) {
inst1 = &c->fp->program.Base.Instructions[insn];
brw_inst1 = inst1->Data;
switch (inst1->Opcode) {
case OPCODE_CAL:
target_insn = inst1->BranchTarget;
inst2 = &c->fp->program.Base.Instructions[target_insn];
brw_inst2 = inst2->Data;
offset = brw_inst2 - brw_inst1;
brw_set_src1(brw_inst1, brw_imm_d(offset*16));
break;
default:
break;
}
}
brw_resolve_cals(&c->func);
}
static void brw_wm_emit_glsl(struct brw_context *brw, struct brw_wm_compile *c)
@ -2293,10 +2277,6 @@ static void brw_wm_emit_glsl(struct brw_context *brw, struct brw_wm_compile *c)
for (i = 0; i < c->nr_fp_insns; i++) {
struct prog_instruction *inst = &c->prog_instructions[i];
struct prog_instruction *orig_inst;
if ((orig_inst = inst->Data) != 0)
orig_inst->Data = current_insn(p);
if (inst->CondUpdate)
brw_set_conditionalmod(p, BRW_CONDITIONAL_NZ);
@ -2454,7 +2434,10 @@ static void brw_wm_emit_glsl(struct brw_context *brw, struct brw_wm_compile *c)
brw_ENDIF(p, if_inst[--if_insn]);
break;
case OPCODE_BGNSUB:
brw_save_label(p, inst->Comment, p->nr_insn);
break;
case OPCODE_ENDSUB:
/* no-op */
break;
case OPCODE_CAL:
brw_push_insn_state(p);
@ -2464,8 +2447,7 @@ static void brw_wm_emit_glsl(struct brw_context *brw, struct brw_wm_compile *c)
brw_set_access_mode(p, BRW_ALIGN_16);
brw_ADD(p, get_addr_reg(stack_index),
get_addr_reg(stack_index), brw_imm_d(4));
orig_inst = inst->Data;
orig_inst->Data = &p->store[p->nr_insn];
brw_save_call(&c->func, inst->Comment, p->nr_insn);
brw_ADD(p, brw_ip_reg(), brw_ip_reg(), brw_imm_d(1*16));
brw_pop_insn_state(p);
break;
@ -2518,8 +2500,6 @@ static void brw_wm_emit_glsl(struct brw_context *brw, struct brw_wm_compile *c)
brw_set_predicate_control(p, BRW_PREDICATE_NONE);
}
post_wm_emit(c);
for (i = 0; i < c->fp->program.Base.NumInstructions; i++)
c->fp->program.Base.Instructions[i].Data = NULL;
}