summaryrefslogtreecommitdiffstats
path: root/src/mesa/shader
diff options
context:
space:
mode:
Diffstat (limited to 'src/mesa/shader')
-rw-r--r--src/mesa/shader/slang/slang_codegen.c110
-rw-r--r--src/mesa/shader/slang/slang_emit.c82
-rw-r--r--src/mesa/shader/slang/slang_ir.h7
-rw-r--r--src/mesa/shader/slang/slang_link.c2
4 files changed, 123 insertions, 78 deletions
diff --git a/src/mesa/shader/slang/slang_codegen.c b/src/mesa/shader/slang/slang_codegen.c
index 42c1f0897eb..14870f57ae8 100644
--- a/src/mesa/shader/slang/slang_codegen.c
+++ b/src/mesa/shader/slang/slang_codegen.c
@@ -1423,7 +1423,7 @@ _slang_gen_while(slang_assemble_ctx * A, const slang_operation *oper)
/**
- * Generate IR tree for a while-loop using high-level LOOP, IF instructions.
+ * Generate loop code using high-level IR_LOOP instruction
*/
static slang_ir_node *
_slang_gen_hl_while(slang_assemble_ctx * A, const slang_operation *oper)
@@ -1510,6 +1510,46 @@ _slang_gen_do(slang_assemble_ctx * A, const slang_operation *oper)
/**
+ * Generate IR tree for a do-while loop using high-level LOOP, IF instructions.
+ */
+static slang_ir_node *
+_slang_gen_hl_do(slang_assemble_ctx * A, const slang_operation *oper)
+{
+ slang_ir_node *prevLoop;
+ /*
+ * LOOP:
+ * body code (child[0])
+ * eval expr (child[1]), updating condcodes
+ * IF !expr:
+ * BRK
+ */
+ slang_ir_node *ifThen, *cond, *body, *loop;
+
+ loop = new_loop(NULL);
+
+ /* save old, push new loop */
+ prevLoop = A->CurLoop;
+ A->CurLoop = loop;
+
+ body = _slang_gen_operation(A, &oper->children[0]);
+
+ cond = _slang_gen_operation(A, &oper->children[1]);
+ cond = new_node1(IR_NOT, cond);
+ cond = _slang_gen_cond(cond);
+
+ ifThen = new_if(cond,
+ new_break(A->CurLoop),
+ NULL);
+
+ loop->Children[0] = new_seq(body, ifThen);
+
+ A->CurLoop = prevLoop; /* pop loop, restore prev */
+
+ return loop;
+}
+
+
+/**
* Generate IR tree for a for-loop.
*/
static slang_ir_node *
@@ -1573,69 +1613,48 @@ _slang_gen_for(slang_assemble_ctx * A, const slang_operation *oper)
/**
- * Generate IR tree for a for-loop, using high-level BGNLOOP/ENDLOOP and
- * IF/ENDIF instructions.
- *
- * XXX note done yet!
+ * Generate for-loop using high-level IR_LOOP instruction.
*/
static slang_ir_node *
_slang_gen_hl_for(slang_assemble_ctx * A, const slang_operation *oper)
{
+ slang_ir_node *prevLoop;
/*
- * init code (child[0])
- * BGNLOOP
+ * init (child[0])
+ * LOOP:
* eval expr (child[1]), updating condcodes
- * IF !expr THEN
+ * IF !expr:
* BRK
- * ENDIF
- * code body (child[3])
- * label "__continueFor" // jump here for "continue"
- * incr code (child[2])
- * ENDLOOP
+ * body code (child[3])
+ * incr code (child[2]) // XXX continue here
*/
- slang_atom startAtom = slang_atom_pool_gen(A->atoms, "__startFor");
- slang_atom contAtom = slang_atom_pool_gen(A->atoms, "__continueFor");
- slang_atom endAtom = slang_atom_pool_gen(A->atoms, "__endFor");
- slang_ir_node *init, *startLab, *cond, *bra, *body, *contLab;
- slang_ir_node *incr, *jump, *endLab, *tree;
- slang_atom prevLoopBreak = A->CurLoopBreak;
- slang_atom prevLoopCont = A->CurLoopCont;
-
- /* Push this loop */
- A->CurLoopBreak = endAtom;
- A->CurLoopCont = contAtom;
+ slang_ir_node *init, *ifThen, *cond, *body, *loop, *incr;
init = _slang_gen_operation(A, &oper->children[0]);
- startLab = new_label(startAtom);
- tree = new_seq(init, startLab);
+ loop = new_loop(NULL);
+
+ /* save old, push new loop */
+ prevLoop = A->CurLoop;
+ A->CurLoop = loop;
cond = _slang_gen_operation(A, &oper->children[1]);
+ cond = new_node1(IR_NOT, cond);
cond = _slang_gen_cond(cond);
- tree = new_seq(tree, cond);
- bra = new_cjump(endAtom, 0);
- tree = new_seq(tree, bra);
+ ifThen = new_if(cond,
+ new_break(A->CurLoop),
+ NULL);
body = _slang_gen_operation(A, &oper->children[3]);
- tree = new_seq(tree, body);
-
- contLab = new_label(contAtom);
- tree = new_seq(tree, contLab);
incr = _slang_gen_operation(A, &oper->children[2]);
- tree = new_seq(tree, incr);
-
- jump = new_jump(startAtom);
- tree = new_seq(tree, jump);
- endLab = new_label(endAtom);
- tree = new_seq(tree, endLab);
+ loop->Children[0] = new_seq(ifThen,
+ new_seq(body,incr));
- /* Pop this loop */
- A->CurLoopBreak = prevLoopBreak;
- A->CurLoopCont = prevLoopCont;
+ A->CurLoop = prevLoop; /* pop loop, restore prev */
- return tree;
+ return new_seq(init, loop);
}
@@ -2434,7 +2453,10 @@ _slang_gen_operation(slang_assemble_ctx * A, slang_operation *oper)
else
return _slang_gen_while(A, oper);
case slang_oper_do:
- return _slang_gen_do(A, oper);
+ if (UseHighLevelInstructions)
+ return _slang_gen_hl_do(A, oper);
+ else
+ return _slang_gen_do(A, oper);
case slang_oper_for:
if (UseHighLevelInstructions)
return _slang_gen_hl_for(A, oper);
diff --git a/src/mesa/shader/slang/slang_emit.c b/src/mesa/shader/slang/slang_emit.c
index 2d5a7cf6f9d..29588379a2f 100644
--- a/src/mesa/shader/slang/slang_emit.c
+++ b/src/mesa/shader/slang/slang_emit.c
@@ -43,6 +43,9 @@
#define ANNOTATE 1
+static GLboolean EmitHighLevelInstructions = GL_FALSE;
+
+
/**
* Assembly and IR info
*/
@@ -1304,57 +1307,72 @@ emit(slang_var_table *vt, slang_ir_node *n, struct gl_program *prog)
case IR_LOOP:
{
struct prog_instruction *beginInst, *endInst;
- GLuint endInstLoc;
- slang_ir_node *p;
+ GLuint beginInstLoc, endInstLoc;
+ slang_ir_node *ir;
- /* save location of this instruction, used by OPCODE_ENDLOOP */
- n->InstLocation = prog->NumInstructions;
- (void) new_instruction(prog, OPCODE_BGNLOOP);
+ /* emit OPCODE_BGNLOOP */
+ beginInstLoc = prog->NumInstructions;
+ if (EmitHighLevelInstructions) {
+ (void) new_instruction(prog, OPCODE_BGNLOOP);
+ }
/* body */
emit(vt, n->Children[0], prog);
endInstLoc = prog->NumInstructions;
- endInst = new_instruction(prog, OPCODE_ENDLOOP);
- /* The ENDLOOP's BranchTarget points to top of loop */
- endInst->BranchTarget = n->InstLocation;
- /* Update BGNLOOP's BranchTarget to point to this instruction */
- beginInst = prog->Instructions + n->InstLocation;
- beginInst->BranchTarget = prog->NumInstructions - 1;
+ if (EmitHighLevelInstructions) {
+ /* emit OPCODE_ENDLOOP */
+ endInst = new_instruction(prog, OPCODE_ENDLOOP);
+ }
+ else {
+ /* emit unconditional BRA-nch */
+ endInst = new_instruction(prog, OPCODE_BRA);
+ endInst->DstReg.CondMask = COND_TR; /* always true */
+ }
+ /* end instruction's BranchTarget points to top of loop */
+ endInst->BranchTarget = beginInstLoc;
+
+ if (EmitHighLevelInstructions) {
+ /* BGNLOOP's BranchTarget points to the ENDLOOP inst */
+ beginInst = prog->Instructions + beginInstLoc;
+ beginInst->BranchTarget = prog->NumInstructions - 1;
+ }
/* Done emitting loop code. Now walk over the loop's linked list
- * of BREAK and CONT nodes, filling in their BranchTarget fields.
+ * of BREAK and CONT nodes, filling in their BranchTarget fields
+ * (which will point to the ENDLOOP or ENDLOOP+1 instructions).
*/
- for (p = n->BranchNode; p; p = p->BranchNode) {
- if (p->Opcode == IR_BREAK) {
- struct prog_instruction *brkInst
- = prog->Instructions + p->InstLocation;
- assert(brkInst->Opcode == OPCODE_BRK);
- brkInst->BranchTarget = endInstLoc + 1;
+ for (ir = n->BranchNode; ir; ir = ir->BranchNode) {
+ struct prog_instruction *inst
+ = prog->Instructions + ir->InstLocation;
+ if (ir->Opcode == IR_BREAK) {
+ assert(inst->Opcode == OPCODE_BRK ||
+ inst->Opcode == OPCODE_BRA);
+ inst->BranchTarget = endInstLoc + 1;
}
else {
- assert(p->Opcode == IR_CONT);
- struct prog_instruction *contInst
- = prog->Instructions + p->InstLocation;
- assert(contInst->Opcode == OPCODE_CONT);
- contInst->BranchTarget = endInstLoc;
+ assert(ir->Opcode == IR_CONT);
+ assert(inst->Opcode == OPCODE_CONT ||
+ inst->Opcode == OPCODE_BRA);
+ inst->BranchTarget = endInstLoc;
}
}
return NULL;
}
- case IR_CONT:
- {
- struct prog_instruction *inst;
- n->InstLocation = prog->NumInstructions;
- inst = new_instruction(prog, OPCODE_CONT);
- inst->DstReg.CondMask = COND_TR; /* always true */
- return inst;
- }
case IR_BREAK:
+ /* fall-through */
+ case IR_CONT:
{
+ gl_inst_opcode opcode;
struct prog_instruction *inst;
n->InstLocation = prog->NumInstructions;
- inst = new_instruction(prog, OPCODE_BRK);
+ if (EmitHighLevelInstructions) {
+ opcode = (n->Opcode == IR_CONT) ? OPCODE_CONT : OPCODE_BRK;
+ }
+ else {
+ opcode = OPCODE_BRA;
+ }
+ inst = new_instruction(prog, opcode);
inst->DstReg.CondMask = COND_TR; /* always true */
return inst;
}
diff --git a/src/mesa/shader/slang/slang_ir.h b/src/mesa/shader/slang/slang_ir.h
index a7c858c69f7..0c827d9cd8c 100644
--- a/src/mesa/shader/slang/slang_ir.h
+++ b/src/mesa/shader/slang/slang_ir.h
@@ -39,7 +39,7 @@
/**
- * Intermediate Representation opcode
+ * Intermediate Representation opcodes
*/
typedef enum
{
@@ -64,6 +64,11 @@ typedef enum
IR_CONT, /* continue loop */
IR_BREAK, /* break loop */
+ IR_BREAK_IF_TRUE,
+ IR_BREAK_IF_FALSE,
+ IR_CONT_IF_TRUE,
+ IR_CONT_IF_FALSE,
+
IR_MOVE,
IR_ADD,
IR_SUB,
diff --git a/src/mesa/shader/slang/slang_link.c b/src/mesa/shader/slang/slang_link.c
index 017cf6078cb..b1d355ff802 100644
--- a/src/mesa/shader/slang/slang_link.c
+++ b/src/mesa/shader/slang/slang_link.c
@@ -298,7 +298,7 @@ _slang_resolve_branches(struct gl_program *prog)
for (i = 0; i < prog->NumInstructions; i++) {
struct prog_instruction *inst = prog->Instructions + i;
- if (inst->Opcode == OPCODE_BRA) {
+ if (inst->Opcode == OPCODE_BRA && inst->BranchTarget < 0) {
for (j = 0; j < numTargets; j++) {
if (!strcmp(inst->Comment, targets[j].Name)) {
inst->BranchTarget = targets[j].Pos;