***/
-#include "imports.h"
-#include "context.h"
-#include "macros.h"
-#include "program.h"
-#include "prog_instruction.h"
-#include "prog_parameter.h"
-#include "prog_print.h"
+#include "main/imports.h"
+#include "main/context.h"
+#include "main/macros.h"
+#include "shader/program.h"
+#include "shader/prog_instruction.h"
+#include "shader/prog_parameter.h"
+#include "shader/prog_print.h"
#include "slang_builtin.h"
#include "slang_emit.h"
+#include "slang_mem.h"
#define PEEPHOLE_OPTIMIZATIONS 1
}
+/**
+ * Convert a writemask to a swizzle. Used for testing cond codes because
+ * we only want to test the cond code component(s) that was set by the
+ * previous instruction.
+ */
+static GLuint
+writemask_to_swizzle(GLuint writemask)
+{
+ if (writemask == WRITEMASK_X)
+ return SWIZZLE_XXXX;
+ if (writemask == WRITEMASK_Y)
+ return SWIZZLE_YYYY;
+ if (writemask == WRITEMASK_Z)
+ return SWIZZLE_ZZZZ;
+ if (writemask == WRITEMASK_W)
+ return SWIZZLE_WWWW;
+ return SWIZZLE_XYZW; /* shouldn't be hit */
+}
+
/**
* Swizzle a swizzle. That is, return swz2(swz1)
_slang_new_ir_storage(enum register_file file, GLint index, GLint size)
{
slang_ir_storage *st;
- st = (slang_ir_storage *) _mesa_calloc(sizeof(slang_ir_storage));
+ st = (slang_ir_storage *) _slang_alloc(sizeof(slang_ir_storage));
if (st) {
st->File = file;
st->Index = index;
if (!_slang_alloc_temp(emitInfo->vt, n->Store)) {
slang_info_log_error(emitInfo->log,
"Ran out of registers, too many temporaries");
+ _slang_free(n->Store);
+ n->Store = NULL;
return GL_FALSE;
}
return GL_TRUE;
_slang_free_temp(vt, n->Store);
n->Store->Index = -1;
n->Store->Size = -1;
+ /*_mesa_free(n->Store);*/ /* XXX leak */
+ n->Store = NULL;
}
}
}
}
+/*
+ * Setup an instrucion src register to point to a scalar constant.
+ */
+static void
+constant_to_src_reg(struct prog_src_register *src, GLfloat val,
+ slang_emit_info *emitInfo)
+{
+ GLuint zeroSwizzle;
+ GLint zeroReg;
+ GLfloat value[4];
+
+ value[0] = val;
+ zeroReg = _mesa_add_unnamed_constant(emitInfo->prog->Parameters,
+ value, 1, &zeroSwizzle);
+ assert(zeroReg >= 0);
+
+ src->File = PROGRAM_CONSTANT;
+ src->Index = zeroReg;
+ src->Swizzle = zeroSwizzle;
+}
+
/**
* Add new instruction at end of given program.
/* normal case */
/* gen code for children */
- for (i = 0; i < info->NumParams; i++)
+ for (i = 0; i < info->NumParams; i++) {
emit(emitInfo, n->Children[i]);
+ if (!n->Children[i] || !n->Children[i]->Store) {
+ /* error recovery */
+ return NULL;
+ }
+ }
/* gen this instruction and src registers */
inst = new_instruction(emitInfo, info->InstOpcode);
/* result storage */
if (!n->Store) {
+ /* XXX this size isn't correct, it depends on the operands */
if (!alloc_temp_storage(emitInfo, n, info->ResultSize))
return NULL;
}
storage_to_dst_reg(&inst->DstReg, n->Store, n->Writemask);
}
else if (size <= 4) {
- static const GLfloat zero[4] = { 0, 0, 0, 0 };
- GLuint zeroSwizzle, swizzle;
- GLint zeroReg = _mesa_add_unnamed_constant(emitInfo->prog->Parameters,
- zero, 4, &zeroSwizzle);
+ GLuint swizzle;
gl_inst_opcode dotOp;
- assert(zeroReg >= 0);
-
+ assert(!n->Store);
if (!n->Store) {
- if (!alloc_temp_storage(emitInfo, n, 4)) /* 4 bools */
+ if (!alloc_temp_storage(emitInfo, n, size)) /* 'size' bools */
return NULL;
}
swizzle = MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Y, SWIZZLE_Y);
}
- /* Compute equality, inequality */
+ /* Compute equality, inequality (tmp1 = (A ?= B)) */
inst = new_instruction(emitInfo, OPCODE_SNE);
storage_to_src_reg(&inst->SrcReg[0], n->Children[0]->Store);
storage_to_src_reg(&inst->SrcReg[1], n->Children[1]->Store);
storage_to_dst_reg(&inst->DstReg, n->Store, n->Writemask);
inst->Comment = _mesa_strdup("Compare values");
- /* compute D = DP4(D, D) (reduction) */
+
+ /* Compute tmp2 = DOT(tmp1, tmp1) (reduction) */
inst = new_instruction(emitInfo, dotOp);
- inst->SrcReg[0].File = PROGRAM_TEMPORARY;
- inst->SrcReg[0].Index = n->Store->Index;
- inst->SrcReg[0].Swizzle = swizzle;
- inst->SrcReg[1].File = PROGRAM_TEMPORARY;
- inst->SrcReg[1].Index = n->Store->Index;
- inst->SrcReg[1].Swizzle = swizzle;
- inst->DstReg.File = PROGRAM_TEMPORARY;
- inst->DstReg.Index = n->Store->Index;
+ storage_to_src_reg(&inst->SrcReg[0], n->Store);
+ storage_to_src_reg(&inst->SrcReg[1], n->Store);
+ inst->SrcReg[0].Swizzle = inst->SrcReg[1].Swizzle = swizzle; /*override*/
+ free_temp_storage(emitInfo->vt, n); /* free tmp1 */
+ if (!alloc_temp_storage(emitInfo, n, 1)) /* alloc tmp2 */
+ return NULL;
+ storage_to_dst_reg(&inst->DstReg, n->Store, n->Writemask);
inst->Comment = _mesa_strdup("Reduce vec to bool");
+
if (n->Opcode == IR_EQUAL) {
- /* compute D.x = !D.x via D.x = (D.x == 0) */
+ /* compute tmp2.x = !tmp2.x via tmp2.x = (tmp2.x == 0) */
inst = new_instruction(emitInfo, OPCODE_SEQ);
- inst->SrcReg[0].File = PROGRAM_TEMPORARY;
- inst->SrcReg[0].Index = n->Store->Index;
- inst->SrcReg[1].File = PROGRAM_CONSTANT;
- inst->SrcReg[1].Index = zeroReg;
- inst->SrcReg[1].Swizzle = zeroSwizzle;
- inst->DstReg.File = PROGRAM_TEMPORARY;
- inst->DstReg.Index = n->Store->Index;
- inst->DstReg.WriteMask = WRITEMASK_X;
+ storage_to_src_reg(&inst->SrcReg[0], n->Store);
+ constant_to_src_reg(&inst->SrcReg[1], 0.0, emitInfo);
+ storage_to_dst_reg(&inst->DstReg, n->Store, n->Writemask);
inst->Comment = _mesa_strdup("Invert true/false");
}
}
emitInfo->prog);
if (emitInfo->EmitBeginEndSub) {
+ /* BGNSUB isn't a real instruction.
+ * We require a label (i.e. "foobar:") though, if we're going to
+ * print the program in the NV format. The BNGSUB instruction is
+ * really just a NOP to attach the label to.
+ */
inst = new_instruction(emitInfo, OPCODE_BGNSUB);
inst->Comment = _mesa_strdup(n->Label->Name);
}
assert(n);
assert(n->Opcode == IR_RETURN);
assert(n->Label);
- 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);
- }
- }
-
+ inst = new_instruction(emitInfo, OPCODE_RET);
+ inst->DstReg.CondMask = COND_TR; /* always return */
return inst;
}
/* Child[0] is the sampler (a uniform which'll indicate the texture unit) */
assert(n->Children[0]->Store);
+ /* Store->Index is the sampler index */
+ assert(n->Children[0]->Store->Index >= 0);
+ /* Store->Size is the texture target */
assert(n->Children[0]->Store->Size >= TEXTURE_1D_INDEX);
+ assert(n->Children[0]->Store->Size <= TEXTURE_RECT_INDEX);
inst->Sampler = n->Children[0]->Store->Index; /* i.e. uniform's index */
inst->TexSrcTarget = n->Children[0]->Store->Size;
/* lhs */
emit(emitInfo, n->Children[0]);
+ if (!n->Children[0]->Store || n->Children[0]->Store->Index < 0) {
+ /* an error should have been already recorded */
+ return NULL;
+ }
/* rhs */
assert(n->Children[1]);
inst = emit(emitInfo, n->Children[1]);
- if (!n->Children[1]->Store) {
- slang_info_log_error(emitInfo->log, "invalid assignment");
+ if (!n->Children[1]->Store || n->Children[1]->Store->Index < 0) {
+ if (!emitInfo->log->text) {
+ slang_info_log_error(emitInfo->log, "invalid assignment");
+ }
return NULL;
}
+
assert(n->Children[1]->Store->Index >= 0);
+ /*assert(n->Children[0]->Store->Size == n->Children[1]->Store->Size);*/
+
n->Store = n->Children[0]->Store;
#if PEEPHOLE_OPTIMIZATIONS
}
+/**
+ * An IR_COND node wraps a boolean expression which is used by an
+ * IF or WHILE test. This is where we'll set condition codes, if needed.
+ */
static struct prog_instruction *
emit_cond(slang_emit_info *emitInfo, slang_ir_node *n)
{
struct prog_instruction *inst;
+ assert(n->Opcode == IR_COND);
+
if (!n->Children[0])
return NULL;
+ /* emit code for the expression */
inst = emit(emitInfo, n->Children[0]);
+ if (!n->Children[0]->Store) {
+ /* error recovery */
+ return NULL;
+ }
+
+ assert(n->Children[0]->Store);
+ /*assert(n->Children[0]->Store->Size == 1);*/
+
if (emitInfo->EmitCondCodes) {
- /* Conditional expression (in if/while/for stmts).
- * Need to update condition code register.
- * Next instruction is typically an IR_IF.
- */
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.
+ * we're testing. Just fix that instruction so that the
+ * condition codes are computed.
*/
inst->CondUpdate = GL_TRUE;
n->Store = n->Children[0]->Store;
/* This'll happen for things like "if (i) ..." where no code
* is normally generated for the expression "i".
* Generate a move instruction just to set condition codes.
- * Note: must use full 4-component vector since all four
- * condition codes must be set identically.
*/
- if (!alloc_temp_storage(emitInfo, n, 4))
+ if (!alloc_temp_storage(emitInfo, n, 1))
return NULL;
inst = new_instruction(emitInfo, OPCODE_MOV);
inst->CondUpdate = GL_TRUE;
storage_to_src_reg(&inst->SrcReg[0], n->Children[0]->Store);
_slang_free_temp(emitInfo->vt, n->Store);
inst->Comment = _mesa_strdup("COND expr");
- return inst; /* XXX or null? */
+ return inst;
}
}
else {
- /* No-op */
+ /* No-op: the boolean result of the expression is in a regular reg */
n->Store = n->Children[0]->Store;
- return NULL;
+ return inst;
}
}
static struct prog_instruction *
emit_not(slang_emit_info *emitInfo, slang_ir_node *n)
{
- GLfloat zero = 0.0;
- slang_ir_storage st;
+ static const struct {
+ gl_inst_opcode op, opNot;
+ } operators[] = {
+ { OPCODE_SLT, OPCODE_SGE },
+ { OPCODE_SLE, OPCODE_SGT },
+ { OPCODE_SGT, OPCODE_SLE },
+ { OPCODE_SGE, OPCODE_SLT },
+ { OPCODE_SEQ, OPCODE_SNE },
+ { OPCODE_SNE, OPCODE_SEQ },
+ { 0, 0 }
+ };
struct prog_instruction *inst;
-
- /* need zero constant */
- st.File = PROGRAM_CONSTANT;
- st.Size = 1;
- st.Index = _mesa_add_unnamed_constant(emitInfo->prog->Parameters, &zero,
- 1, &st.Swizzle);
+ GLuint i;
/* child expr */
- (void) emit(emitInfo, n->Children[0]);
- /* XXXX if child instr is SGT convert to SLE, if SEQ, SNE, etc */
+ inst = emit(emitInfo, n->Children[0]);
+
+#if PEEPHOLE_OPTIMIZATIONS
+ if (inst) {
+ /* if the prev instruction was a comparison instruction, invert it */
+ for (i = 0; operators[i].op; i++) {
+ if (inst->Opcode == operators[i].op) {
+ inst->Opcode = operators[i].opNot;
+ n->Store = n->Children[0]->Store;
+ return inst;
+ }
+ }
+ }
+#endif
+ /* else, invert using SEQ (v = v == 0) */
if (!n->Store)
if (!alloc_temp_storage(emitInfo, n, n->Children[0]->Store->Size))
return NULL;
inst = new_instruction(emitInfo, OPCODE_SEQ);
storage_to_dst_reg(&inst->DstReg, n->Store, n->Writemask);
storage_to_src_reg(&inst->SrcReg[0], n->Children[0]->Store);
- storage_to_src_reg(&inst->SrcReg[1], &st);
-
+ constant_to_src_reg(&inst->SrcReg[1], 0.0, emitInfo);
free_temp_storage(emitInfo->vt, n->Children[0]);
inst->Comment = _mesa_strdup("NOT");
emit_if(slang_emit_info *emitInfo, slang_ir_node *n)
{
struct gl_program *prog = emitInfo->prog;
- struct prog_instruction *ifInst;
GLuint ifInstLoc, elseInstLoc = 0;
+ GLuint condWritemask = 0;
- emit(emitInfo, n->Children[0]); /* the condition */
+ /* emit condition expression code */
+ {
+ struct prog_instruction *inst;
+ inst = emit(emitInfo, n->Children[0]);
+ if (emitInfo->EmitCondCodes) {
+ if (!inst) {
+ /* error recovery */
+ return NULL;
+ }
+ condWritemask = inst->DstReg.WriteMask;
+ }
+ }
#if 0
assert(n->Children[0]->Store->Size == 1); /* a bool! */
ifInstLoc = prog->NumInstructions;
if (emitInfo->EmitHighLevelInstructions) {
- ifInst = new_instruction(emitInfo, OPCODE_IF);
+ struct prog_instruction *ifInst = new_instruction(emitInfo, OPCODE_IF);
if (emitInfo->EmitCondCodes) {
ifInst->DstReg.CondMask = COND_NE; /* if cond is non-zero */
+ /* only test the cond code (1 of 4) that was updated by the
+ * previous instruction.
+ */
+ ifInst->DstReg.CondSwizzle = writemask_to_swizzle(condWritemask);
}
else {
/* test reg.x */
}
else {
/* conditional jump to else, or endif */
- ifInst = new_instruction(emitInfo, OPCODE_BRA);
+ struct prog_instruction *ifInst = new_instruction(emitInfo, OPCODE_BRA);
ifInst->DstReg.CondMask = COND_EQ; /* BRA if cond is zero */
ifInst->Comment = _mesa_strdup("if zero");
- }
- if (emitInfo->EmitCondCodes) {
- /* which condition code to use: */
- ifInst->DstReg.CondSwizzle = n->Children[0]->Store->Swizzle;
+ ifInst->DstReg.CondSwizzle = writemask_to_swizzle(condWritemask);
}
/* if body */
inst->Comment = _mesa_strdup("else");
inst->DstReg.CondMask = COND_TR; /* always branch */
}
- ifInst = prog->Instructions + ifInstLoc;
- ifInst->BranchTarget = prog->NumInstructions;
-
+ prog->Instructions[ifInstLoc].BranchTarget = prog->NumInstructions;
emit(emitInfo, n->Children[2]);
}
else {
/* no else body */
- ifInst = prog->Instructions + ifInstLoc;
- ifInst->BranchTarget = prog->NumInstructions + 1;
+ prog->Instructions[ifInstLoc].BranchTarget = prog->NumInstructions;
}
if (emitInfo->EmitHighLevelInstructions) {
}
if (n->Children[2]) {
- struct prog_instruction *elseInst;
- elseInst = prog->Instructions + elseInstLoc;
- elseInst->BranchTarget = prog->NumInstructions;
+ prog->Instructions[elseInstLoc].BranchTarget = prog->NumInstructions;
}
return NULL;
}
emit_loop(slang_emit_info *emitInfo, slang_ir_node *n)
{
struct gl_program *prog = emitInfo->prog;
- struct prog_instruction *beginInst, *endInst;
+ struct prog_instruction *endInst;
GLuint beginInstLoc, tailInstLoc, endInstLoc;
slang_ir_node *ir;
if (emitInfo->EmitHighLevelInstructions) {
/* BGNLOOP's BranchTarget points to the ENDLOOP inst */
- beginInst = prog->Instructions + beginInstLoc;
- beginInst->BranchTarget = prog->NumInstructions - 1;
+ prog->Instructions[beginInstLoc].BranchTarget = prog->NumInstructions -1;
}
/* Done emitting loop code. Now walk over the loop's linked list of
struct prog_instruction *inst = prog->Instructions + ir->InstLocation;
assert(inst->BranchTarget < 0);
if (ir->Opcode == IR_BREAK ||
- ir->Opcode == IR_BREAK_IF_FALSE ||
ir->Opcode == IR_BREAK_IF_TRUE) {
assert(inst->Opcode == OPCODE_BRK ||
- inst->Opcode == OPCODE_BRK0 ||
- inst->Opcode == OPCODE_BRK1 ||
inst->Opcode == OPCODE_BRA);
/* go to instruction after end of loop */
inst->BranchTarget = endInstLoc + 1;
}
else {
assert(ir->Opcode == IR_CONT ||
- ir->Opcode == IR_CONT_IF_FALSE ||
ir->Opcode == IR_CONT_IF_TRUE);
assert(inst->Opcode == OPCODE_CONT ||
- inst->Opcode == OPCODE_CONT0 ||
- inst->Opcode == OPCODE_CONT1 ||
inst->Opcode == OPCODE_BRA);
/* go to instruction at tail of loop */
inst->BranchTarget = endInstLoc;
* Either OPCODE_CONT, OPCODE_BRK or OPCODE_BRA will be emitted.
*/
static struct prog_instruction *
-emit_cont_break_if(slang_emit_info *emitInfo, slang_ir_node *n,
- GLboolean breakTrue)
+emit_cont_break_if_true(slang_emit_info *emitInfo, slang_ir_node *n)
{
- gl_inst_opcode opcode;
struct prog_instruction *inst;
assert(n->Opcode == IR_CONT_IF_TRUE ||
- n->Opcode == IR_CONT_IF_FALSE ||
- n->Opcode == IR_BREAK_IF_TRUE ||
- n->Opcode == IR_BREAK_IF_FALSE);
+ n->Opcode == IR_BREAK_IF_TRUE);
/* evaluate condition expr, setting cond codes */
inst = emit(emitInfo, n->Children[0]);
/* opcode selection */
if (emitInfo->EmitHighLevelInstructions) {
+ const gl_inst_opcode opcode
+ = (n->Opcode == IR_CONT_IF_TRUE) ? OPCODE_CONT : OPCODE_BRK;
if (emitInfo->EmitCondCodes) {
- if (n->Opcode == IR_CONT_IF_TRUE ||
- n->Opcode == IR_CONT_IF_FALSE)
- opcode = OPCODE_CONT;
- else
- opcode = OPCODE_BRK;
+ /* Get the writemask from the previous instruction which set
+ * the condcodes. Use that writemask as the CondSwizzle.
+ */
+ const GLuint condWritemask = inst->DstReg.WriteMask;
+ inst = new_instruction(emitInfo, opcode);
+ inst->DstReg.CondMask = COND_NE;
+ inst->DstReg.CondSwizzle = writemask_to_swizzle(condWritemask);
+ return inst;
}
else {
- if (n->Opcode == IR_CONT_IF_TRUE)
- opcode = OPCODE_CONT1;
- else if (n->Opcode == IR_CONT_IF_FALSE)
- opcode = OPCODE_CONT0;
- else if (n->Opcode == IR_BREAK_IF_TRUE)
- opcode = OPCODE_BRK1;
- else if (n->Opcode == IR_BREAK_IF_FALSE)
- opcode = OPCODE_BRK0;
- }
- }
- else {
- opcode = OPCODE_BRA;
- }
+ /* IF reg
+ * BRK/CONT;
+ * ENDIF
+ */
+ GLint ifInstLoc;
+ ifInstLoc = emitInfo->prog->NumInstructions;
+ inst = new_instruction(emitInfo, OPCODE_IF);
+ storage_to_src_reg(&inst->SrcReg[0], n->Children[0]->Store);
+ n->InstLocation = emitInfo->prog->NumInstructions;
- inst = new_instruction(emitInfo, opcode);
- if (emitInfo->EmitCondCodes) {
- inst->DstReg.CondMask = breakTrue ? COND_NE : COND_EQ;
+ inst = new_instruction(emitInfo, opcode);
+ inst = new_instruction(emitInfo, OPCODE_ENDIF);
+
+ emitInfo->prog->Instructions[ifInstLoc].BranchTarget
+ = emitInfo->prog->NumInstructions;
+ return inst;
+ }
}
else {
- /* BRK0, BRK1, CONT0, CONT1 uses SrcReg[0] as the condition */
- storage_to_src_reg(&inst->SrcReg[0], n->Children[0]->Store);
+ const GLuint condWritemask = inst->DstReg.WriteMask;
+ assert(emitInfo->EmitCondCodes);
+ inst = new_instruction(emitInfo, OPCODE_BRA);
+ inst->DstReg.CondMask = COND_NE;
+ inst->DstReg.CondSwizzle = writemask_to_swizzle(condWritemask);
+ return inst;
}
- return inst;
}
}
if (n->Store->Index < 0) {
- printf("#### VAR %s not allocated!\n", (char*)n->Var->a_name);
+ /* probably ran out of registers */
+ return NULL;
}
- assert(n->Store->Index >= 0);
assert(n->Store->Size > 0);
break;
case IR_LOOP:
return emit_loop(emitInfo, n);
- case IR_BREAK_IF_FALSE:
- case IR_CONT_IF_FALSE:
- return emit_cont_break_if(emitInfo, n, GL_FALSE);
case IR_BREAK_IF_TRUE:
case IR_CONT_IF_TRUE:
- return emit_cont_break_if(emitInfo, n, GL_TRUE);
+ return emit_cont_break_if_true(emitInfo, n);
case IR_BREAK:
/* fall-through */
case IR_CONT:
mainP->Instructions = _mesa_realloc_instructions(mainP->Instructions,
mainP->NumInstructions,
total);
+ 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->Parameters = NULL; /* prevent double-free */
_mesa_delete_program(ctx, sub);
}
- mainP->NumInstructions = total;
+
+ /* free subroutine list */
+ if (emitInfo->Subroutines) {
+ _mesa_free(emitInfo->Subroutines);
+ emitInfo->Subroutines = NULL;
+ }
+ emitInfo->NumSubroutines = 0;
/* Examine CAL instructions.
* At this point, the BranchTarget field of the CAL instructions is
emitInfo.EmitHighLevelInstructions = ctx->Shader.EmitHighLevelInstructions;
emitInfo.EmitCondCodes = ctx->Shader.EmitCondCodes;
emitInfo.EmitComments = ctx->Shader.EmitComments;
- emitInfo.EmitBeginEndSub = 0; /* XXX for compiler debug only */
+ emitInfo.EmitBeginEndSub = GL_TRUE;
+
+ if (!emitInfo.EmitCondCodes) {
+ emitInfo.EmitHighLevelInstructions = GL_TRUE;
+ }
(void) emit(&emitInfo, n);