diff options
Diffstat (limited to 'src/mesa/shader/slang/slang_emit.c')
-rw-r--r-- | src/mesa/shader/slang/slang_emit.c | 380 |
1 files changed, 229 insertions, 151 deletions
diff --git a/src/mesa/shader/slang/slang_emit.c b/src/mesa/shader/slang/slang_emit.c index c997c11a7d..9991a7caee 100644 --- a/src/mesa/shader/slang/slang_emit.c +++ b/src/mesa/shader/slang/slang_emit.c @@ -126,21 +126,6 @@ _slang_swizzle_swizzle(GLuint swz1, GLuint swz2) } -slang_ir_storage * -_slang_new_ir_storage(enum register_file file, GLint index, GLint size) -{ - slang_ir_storage *st; - st = (slang_ir_storage *) _slang_alloc(sizeof(slang_ir_storage)); - if (st) { - st->File = file; - st->Index = index; - st->Size = size; - st->Swizzle = SWIZZLE_NOOP; - } - return st; -} - - /** * Allocate temporary storage for an intermediate result (such as for * a multiply or add, etc. @@ -176,14 +161,45 @@ free_temp_storage(slang_var_table *vt, slang_ir_node *n) if (_slang_is_temp(vt, n->Store)) { _slang_free_temp(vt, n->Store); n->Store->Index = -1; - n->Store->Size = -1; - /*_mesa_free(n->Store);*/ /* XXX leak */ - n->Store = NULL; + n->Store = NULL; /* XXX this may not be needed */ } } } + +/** + * Remove any SWIZZLE_NIL terms from given swizzle mask. + * For a swizzle like .z??? generate .zzzz (replicate single component). + * Else, for .wx?? generate .wxzw (insert default component for the position). + */ +static GLuint +fix_swizzle(GLuint swizzle) +{ + GLuint c0 = GET_SWZ(swizzle, 0), + c1 = GET_SWZ(swizzle, 1), + c2 = GET_SWZ(swizzle, 2), + c3 = GET_SWZ(swizzle, 3); + if (c1 == SWIZZLE_NIL && c2 == SWIZZLE_NIL && c3 == SWIZZLE_NIL) { + /* smear first component across all positions */ + c1 = c2 = c3 = c0; + } + else { + /* insert default swizzle components */ + if (c0 == SWIZZLE_NIL) + c0 = SWIZZLE_X; + if (c1 == SWIZZLE_NIL) + c1 = SWIZZLE_Y; + if (c2 == SWIZZLE_NIL) + c2 = SWIZZLE_Z; + if (c3 == SWIZZLE_NIL) + c3 = SWIZZLE_W; + } + return MAKE_SWIZZLE4(c0, c1, c2, c3); +} + + + /** * Convert IR storage to an instruction dst register. */ @@ -191,14 +207,28 @@ static void storage_to_dst_reg(struct prog_dst_register *dst, const slang_ir_storage *st, GLuint writemask) { - assert(st->Index >= 0); - dst->File = st->File; - dst->Index = st->Index; + const GLint size = st->Size; + GLint index = st->Index; + GLuint swizzle = st->Swizzle; + + /* if this is storage relative to some parent storage, walk up the tree */ + while (st->Parent) { + st = st->Parent; + index += st->Index; + swizzle = _slang_swizzle_swizzle(st->Swizzle, swizzle); + } + assert(st->File != PROGRAM_UNDEFINED); - assert(st->Size >= 1); - assert(st->Size <= 4); - if (st->Size == 1) { - GLuint comp = GET_SWZ(st->Swizzle, 0); + dst->File = st->File; + + assert(index >= 0); + dst->Index = index; + + assert(size >= 1); + assert(size <= 4); + + if (size == 1) { + GLuint comp = GET_SWZ(swizzle, 0); assert(comp < 4); dst->WriteMask = WRITEMASK_X << comp; } @@ -214,28 +244,38 @@ storage_to_dst_reg(struct prog_dst_register *dst, const slang_ir_storage *st, static void storage_to_src_reg(struct prog_src_register *src, const slang_ir_storage *st) { - static const GLuint defaultSwizzle[4] = { - MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_X, SWIZZLE_X, SWIZZLE_X), - MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_W), - MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_W), - MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_W) - }; + const GLboolean relAddr = st->RelAddr; + GLint index = st->Index; + GLuint swizzle = st->Swizzle; + + /* if this is storage relative to some parent storage, walk up the tree */ + while (st->Parent) { + st = st->Parent; + index += st->Index; + swizzle = _slang_swizzle_swizzle(st->Swizzle, swizzle); + } + assert(st->File >= 0); +#if 1 /* XXX temporary */ + if (st->File == PROGRAM_UNDEFINED) { + slang_ir_storage *st0 = (slang_ir_storage *) st; + st0->File = PROGRAM_TEMPORARY; + } +#endif assert(st->File < PROGRAM_UNDEFINED); - assert(st->Size >= 1); - assert(st->Size <= 4); src->File = st->File; - src->Index = st->Index; - src->RelAddr = st->RelAddr; - if (st->Swizzle != SWIZZLE_NOOP) - src->Swizzle = st->Swizzle; - else - src->Swizzle = defaultSwizzle[st->Size - 1]; /*XXX really need this?*/ - assert(GET_SWZ(src->Swizzle, 0) <= 3); - assert(GET_SWZ(src->Swizzle, 1) <= 3); - assert(GET_SWZ(src->Swizzle, 2) <= 3); - assert(GET_SWZ(src->Swizzle, 3) <= 3); + assert(index >= 0); + src->Index = index; + + swizzle = fix_swizzle(swizzle); + assert(GET_SWZ(swizzle, 0) <= SWIZZLE_W); + assert(GET_SWZ(swizzle, 1) <= SWIZZLE_W); + assert(GET_SWZ(swizzle, 2) <= SWIZZLE_W); + assert(GET_SWZ(swizzle, 3) <= SWIZZLE_W); + src->Swizzle = swizzle; + + src->RelAddr = relAddr; } @@ -545,10 +585,17 @@ emit_arith(slang_emit_info *emitInfo, slang_ir_node *n) /* result storage */ if (!n->Store) { - GLint size = n->Children[0]->Store - ? n->Children[0]->Store->Size : info->ResultSize; + GLint size = info->ResultSize; if (!alloc_temp_storage(emitInfo, n, size)) return NULL; +#if 0000 /* this should work, but doesn't yet */ + if (size == 2) + n->Writemask = WRITEMASK_XY; + else if (size == 3) + n->Writemask = WRITEMASK_XYZ; + else if (size == 1) + n->Writemask = WRITEMASK_X << GET_SWZ(n->Store->Swizzle,0); +#endif } storage_to_dst_reg(&inst->DstReg, n->Store, n->Writemask); @@ -584,7 +631,11 @@ emit_compare(slang_emit_info *emitInfo, slang_ir_node *n) emit(emitInfo, n->Children[0]); emit(emitInfo, n->Children[1]); - assert(n->Children[0]->Store->Size == n->Children[1]->Store->Size); + if (n->Children[0]->Store->Size != n->Children[1]->Store->Size) { + slang_info_log_error(emitInfo->log, "invalid operands to == or !="); + return NULL; + } + size = n->Children[0]->Store->Size; if (size == 1) { @@ -653,29 +704,72 @@ emit_compare(slang_emit_info *emitInfo, slang_ir_node *n) } } else { - /* size > 4, struct compare */ -#if 0 + /* size > 4, struct or array compare. + * XXX this won't work reliably for structs with padding!! + */ GLint i, num = (n->Children[0]->Store->Size + 3) / 4; - /*printf("BEGIN COMPARE size %d\n", num);*/ + slang_ir_storage accTemp; + + if (!n->Store) { + if (!alloc_temp_storage(emitInfo, n, 4)) + return NULL; + } + + accTemp.Size = 4; + accTemp.File = PROGRAM_TEMPORARY; + if (!_slang_alloc_temp(emitInfo->vt, &accTemp)) { + return NULL; + /* out of temps */ + } + for (i = 0; i < num; i++) { - inst = new_instruction(emitInfo, opcode); - inst->SrcReg[0].File = n->Children[0]->Store->File; - inst->SrcReg[0].Index = n->Children[0]->Store->Index + i; - inst->SrcReg[1].File = n->Children[1]->Store->File; - inst->SrcReg[1].Index = n->Children[1]->Store->Index + i; - inst->DstReg.File = n->Store->File; - inst->DstReg.Index = n->Store->Index; - - inst->CondUpdate = 1; /* update cond code */ + /* SNE t0, left[i], right[i] */ + 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); + inst->SrcReg[0].Index += i; + inst->SrcReg[1].Index += i; + if (i == 0) { + inst->DstReg.File = accTemp.File; + inst->DstReg.Index = accTemp.Index; + inst->Comment = _mesa_strdup("Begin struct/array comparison"); + } + else { + inst->DstReg.File = n->Store->File; + inst->DstReg.Index = n->Store->Index; + } if (i > 0) { - inst->DstReg.CondMask = COND_NE; /* update if !=0 */ + /* ADD accTemp, accTemp, temp; # like logical-OR */ + inst = new_instruction(emitInfo, OPCODE_ADD); + inst->SrcReg[0].File = accTemp.File; + inst->SrcReg[0].Index = accTemp.Index; + inst->SrcReg[1].File = n->Store->File; + inst->SrcReg[1].Index = n->Store->Index; + inst->DstReg.File = accTemp.File; + inst->DstReg.Index = accTemp.Index; } - /*_mesa_print_instruction(inst);*/ } - storage_to_dst_reg(&inst->DstReg, n->Store, n->Writemask); -#endif - _mesa_problem(NULL, "struct comparison not implemented yet"); - inst = NULL; + + /* compute accTemp.x || accTemp.y || accTemp.z || accTemp.w with DOT4 */ + inst = new_instruction(emitInfo, OPCODE_DP4); + inst->SrcReg[0].File = accTemp.File; + inst->SrcReg[0].Index = accTemp.Index; + inst->SrcReg[1].File = accTemp.File; + inst->SrcReg[1].Index = accTemp.Index; + inst->DstReg.File = n->Store->File; + inst->DstReg.Index = n->Store->Index; + inst->Comment = _mesa_strdup("End struct/array comparison"); + + if (n->Opcode == IR_EQUAL) { + /* compute tmp.x = !tmp.x via tmp.x = (tmp.x == 0) */ + inst = new_instruction(emitInfo, OPCODE_SEQ); + 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"); + } + + _slang_free_temp(emitInfo->vt, &accTemp); } /* free temps */ @@ -927,7 +1021,7 @@ emit_tex(slang_emit_info *emitInfo, slang_ir_node *n) storage_to_dst_reg(&inst->DstReg, n->Store, n->Writemask); /* Child[1] is the coord */ - assert(n->Children[1]->Store->File != PROGRAM_UNDEFINED); + /*assert(n->Children[1]->Store->File != PROGRAM_UNDEFINED);*/ assert(n->Children[1]->Store->Index >= 0); storage_to_src_reg(&inst->SrcReg[0], n->Children[1]->Store); @@ -957,6 +1051,8 @@ emit_move(slang_emit_info *emitInfo, slang_ir_node *n) { struct prog_instruction *inst; + assert(n->Opcode == IR_MOVE); + /* lhs */ emit(emitInfo, n->Children[0]); if (!n->Children[0]->Store || n->Children[0]->Store->Index < 0) { @@ -995,8 +1091,14 @@ emit_move(slang_emit_info *emitInfo, slang_ir_node *n) 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 previous instruction (which stored the RHS result) */ assert(n->Children[0]->Store->Index >= 0); + + /* use tighter writemask when possible */ + if (n->Writemask == WRITEMASK_XYZW) + n->Writemask = inst->DstReg.WriteMask; + storage_to_dst_reg(&inst->DstReg, n->Children[0]->Store, n->Writemask); return inst; } @@ -1174,6 +1276,9 @@ emit_if(slang_emit_info *emitInfo, slang_ir_node *n) } } + if (!n->Children[0]->Store) + return NULL; + #if 0 assert(n->Children[0]->Store->Size == 1); /* a bool! */ #endif @@ -1408,75 +1513,18 @@ emit_cont_break_if_true(slang_emit_info *emitInfo, slang_ir_node *n) } - -/** - * Remove any SWIZZLE_NIL terms from given swizzle mask (smear prev term). - * Ex: fix_swizzle("zyNN") -> "zyyy" - */ -static GLuint -fix_swizzle(GLuint swizzle) -{ - GLuint swz[4], i; - for (i = 0; i < 4; i++) { - swz[i] = GET_SWZ(swizzle, i); - if (swz[i] == SWIZZLE_NIL) { - swz[i] = swz[i - 1]; - } - } - return MAKE_SWIZZLE4(swz[0], swz[1], swz[2], swz[3]); -} - - -/** - * Return the number of components actually named by the swizzle. - * Recall that swizzles may have undefined/don't-care values. - */ -static GLuint -swizzle_size(GLuint swizzle) -{ - GLuint size = 0, i; - for (i = 0; i < 4; i++) { - GLuint swz = GET_SWZ(swizzle, i); - size += (swz >= 0 && swz <= 3); - } - return size; -} - - static struct prog_instruction * emit_swizzle(slang_emit_info *emitInfo, slang_ir_node *n) { - GLuint swizzle; struct prog_instruction *inst; inst = emit(emitInfo, n->Children[0]); -#ifdef DEBUG - { - GLuint s = n->Children[0]->Store->Swizzle; - assert(GET_SWZ(s, 0) != SWIZZLE_NIL); - assert(GET_SWZ(s, 1) != SWIZZLE_NIL); - assert(GET_SWZ(s, 2) != SWIZZLE_NIL); - assert(GET_SWZ(s, 3) != SWIZZLE_NIL); - } -#endif - /* For debug: n->Var = n->Children[0]->Var; */ - - /* "pull-up" the child's storage info, applying our swizzle info */ - n->Store->File = n->Children[0]->Store->File; - n->Store->Index = n->Children[0]->Store->Index; - n->Store->Size = swizzle_size(n->Store->Swizzle); -#if 0 - 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); -#endif + /* setup storage info, if needed */ + if (!n->Store->Parent) + n->Store->Parent = n->Children[0]->Store; - /* apply this swizzle to child's swizzle to get composed swizzle */ - swizzle = fix_swizzle(n->Store->Swizzle); /* remove the don't care terms */ - n->Store->Swizzle = _slang_swizzle_swizzle(n->Children[0]->Store->Swizzle, - swizzle); + assert(n->Store->Parent); return inst; } @@ -1489,33 +1537,61 @@ emit_swizzle(slang_emit_info *emitInfo, slang_ir_node *n) static struct prog_instruction * emit_array_element(slang_emit_info *emitInfo, slang_ir_node *n) { + slang_ir_storage *root; + + assert(n->Opcode == IR_ELEMENT); assert(n->Store); - assert(n->Store->File != PROGRAM_UNDEFINED); + assert(n->Store->File == PROGRAM_UNDEFINED); + assert(n->Store->Parent); assert(n->Store->Size > 0); - if (n->Store->File == PROGRAM_STATE_VAR) { - n->Store->Index = _slang_alloc_statevar(n, emitInfo->prog->Parameters); + root = n->Store; + while (root->Parent) + root = root->Parent; + + if (root->File == PROGRAM_STATE_VAR) { + GLint index = _slang_alloc_statevar(n, emitInfo->prog->Parameters); + assert(n->Store->Index == index); return NULL; } + /* do codegen for array */ + emit(emitInfo, n->Children[0]); + if (n->Children[1]->Opcode == IR_FLOAT) { - /* Constant index */ - const GLint arrayAddr = n->Children[0]->Store->Index; - const GLint index = (GLint) n->Children[1]->Value[0]; - n->Store->Index = arrayAddr + index; + /* Constant array index. + * Set Store's index to be the offset of the array element in + * the register file. + */ + const GLint element = (GLint) n->Children[1]->Value[0]; + const GLint sz = (n->Store->Size + 3) / 4; /* size in slots/registers */ + + n->Store->Index = sz * element; + assert(n->Store->Parent); } else { - /* Variable index*/ + /* Variable array index */ struct prog_instruction *inst; + + /* do codegen for array index expression */ + emit(emitInfo, n->Children[1]); + inst = new_instruction(emitInfo, OPCODE_ARL); + storage_to_dst_reg(&inst->DstReg, n->Store, n->Writemask); storage_to_src_reg(&inst->SrcReg[0], n->Children[1]->Store); + inst->DstReg.File = PROGRAM_ADDRESS; + inst->DstReg.Index = 0; /* always address register [0] */ inst->Comment = _mesa_strdup("ARL ADDR"); + n->Store->RelAddr = GL_TRUE; - n->Store->Index = inst->DstReg.Index;/*index of the array*/ - inst->DstReg.Index = 0; /*addr index is always 0*/ } + + /* if array element size is one, make sure we only access X */ + if (n->Store->Size == 1) + n->Store->Swizzle = SWIZZLE_XXXX; + return NULL; /* no instruction */ } @@ -1526,25 +1602,27 @@ emit_array_element(slang_emit_info *emitInfo, slang_ir_node *n) static struct prog_instruction * emit_struct_field(slang_emit_info *emitInfo, slang_ir_node *n) { - if (n->Store->File == PROGRAM_STATE_VAR) { - n->Store->Index = _slang_alloc_statevar(n, emitInfo->prog->Parameters); - if (n->Store->Index < 0) { + slang_ir_storage *root = n->Store; + + assert(n->Opcode == IR_FIELD); + + while (root->Parent) + root = root->Parent; + + /* If this is the field of a state var, allocate constant/uniform + * storage for it now if we haven't already. + * Note that we allocate storage (uniform/constant slots) for state + * variables here rather than at declaration time so we only allocate + * space for the ones that we actually use! + */ + if (root->File == PROGRAM_STATE_VAR) { + root->Index = _slang_alloc_statevar(n, emitInfo->prog->Parameters); + if (root->Index < 0) { slang_info_log_error(emitInfo->log, "Error parsing state variable"); return NULL; } } - else { - GLint offset = n->FieldOffset / 4; - assert(n->Children[0]->Store->Index >= 0); - n->Store->Index = n->Children[0]->Store->Index + offset; - if (n->Store->Size == 1) { - GLint swz = n->FieldOffset % 4; - n->Store->Swizzle = MAKE_SWIZZLE4(swz, swz, swz, swz); - } - else { - n->Store->Swizzle = SWIZZLE_XYZW; - } - } + return NULL; /* no instruction */ } |