Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenslang_emit.c
Go to the documentation of this file.
00001 /* 00002 * Mesa 3-D graphics library 00003 * 00004 * Copyright (C) 2005-2008 Brian Paul All Rights Reserved. 00005 * Copyright (C) 2008 VMware, Inc. All Rights Reserved. 00006 * 00007 * Permission is hereby granted, free of charge, to any person obtaining a 00008 * copy of this software and associated documentation files (the "Software"), 00009 * to deal in the Software without restriction, including without limitation 00010 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 00011 * and/or sell copies of the Software, and to permit persons to whom the 00012 * Software is furnished to do so, subject to the following conditions: 00013 * 00014 * The above copyright notice and this permission notice shall be included 00015 * in all copies or substantial portions of the Software. 00016 * 00017 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 00018 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 00019 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 00020 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 00021 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 00022 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 00023 */ 00024 00031 /*** 00032 *** NOTES 00033 *** 00034 *** To emit GPU instructions, we basically just do an in-order traversal 00035 *** of the IR tree. 00036 ***/ 00037 00038 00039 #include "main/imports.h" 00040 #include "main/context.h" 00041 #include "main/macros.h" 00042 #include "shader/program.h" 00043 #include "shader/prog_instruction.h" 00044 #include "shader/prog_parameter.h" 00045 #include "shader/prog_print.h" 00046 #include "slang_builtin.h" 00047 #include "slang_emit.h" 00048 #include "slang_mem.h" 00049 00050 00051 #define PEEPHOLE_OPTIMIZATIONS 1 00052 #define ANNOTATE 0 00053 00054 00055 typedef struct 00056 { 00057 slang_info_log *log; 00058 slang_var_table *vt; 00059 struct gl_program *prog; 00060 struct gl_program **Subroutines; 00061 GLuint NumSubroutines; 00062 00063 GLuint MaxInstructions; 00065 /* code-gen options */ 00066 GLboolean EmitHighLevelInstructions; 00067 GLboolean EmitCondCodes; 00068 GLboolean EmitComments; 00069 GLboolean EmitBeginEndSub; /* XXX TEMPORARY */ 00070 } slang_emit_info; 00071 00072 00073 00074 static struct gl_program * 00075 new_subroutine(slang_emit_info *emitInfo, GLuint *id) 00076 { 00077 GET_CURRENT_CONTEXT(ctx); 00078 const GLuint n = emitInfo->NumSubroutines; 00079 00080 emitInfo->Subroutines = (struct gl_program **) 00081 _mesa_realloc(emitInfo->Subroutines, 00082 n * sizeof(struct gl_program), 00083 (n + 1) * sizeof(struct gl_program)); 00084 emitInfo->Subroutines[n] = ctx->Driver.NewProgram(ctx, emitInfo->prog->Target, 0); 00085 emitInfo->Subroutines[n]->Parameters = emitInfo->prog->Parameters; 00086 emitInfo->NumSubroutines++; 00087 *id = n; 00088 return emitInfo->Subroutines[n]; 00089 } 00090 00091 00097 static GLuint 00098 writemask_to_swizzle(GLuint writemask) 00099 { 00100 if (writemask == WRITEMASK_X) 00101 return SWIZZLE_XXXX; 00102 if (writemask == WRITEMASK_Y) 00103 return SWIZZLE_YYYY; 00104 if (writemask == WRITEMASK_Z) 00105 return SWIZZLE_ZZZZ; 00106 if (writemask == WRITEMASK_W) 00107 return SWIZZLE_WWWW; 00108 return SWIZZLE_XYZW; /* shouldn't be hit */ 00109 } 00110 00111 00122 static GLuint 00123 swizzle_to_writemask(GLuint swizzle) 00124 { 00125 GLuint i, writemask = 0x0; 00126 for (i = 0; i < 4; i++) { 00127 GLuint swz = GET_SWZ(swizzle, i); 00128 if (swz <= SWIZZLE_W) { 00129 writemask |= (1 << swz); 00130 } 00131 } 00132 return writemask; 00133 } 00134 00135 00141 GLuint 00142 _slang_swizzle_swizzle(GLuint swz1, GLuint swz2) 00143 { 00144 GLuint i, swz, s[4]; 00145 for (i = 0; i < 4; i++) { 00146 GLuint c = GET_SWZ(swz2, i); 00147 if (c <= SWIZZLE_W) 00148 s[i] = GET_SWZ(swz1, c); 00149 else 00150 s[i] = c; 00151 } 00152 swz = MAKE_SWIZZLE4(s[0], s[1], s[2], s[3]); 00153 return swz; 00154 } 00155 00156 00162 GLuint 00163 _slang_var_swizzle(GLint size, GLint comp) 00164 { 00165 switch (size) { 00166 case 1: 00167 return MAKE_SWIZZLE4(comp, SWIZZLE_NIL, SWIZZLE_NIL, SWIZZLE_NIL); 00168 case 2: 00169 return MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_NIL, SWIZZLE_NIL); 00170 case 3: 00171 return MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_NIL); 00172 default: 00173 return SWIZZLE_XYZW; 00174 } 00175 } 00176 00177 00178 00188 static GLboolean 00189 alloc_node_storage(slang_emit_info *emitInfo, slang_ir_node *n, 00190 GLint defaultSize) 00191 { 00192 assert(!n->Var); 00193 if (!n->Store) { 00194 assert(defaultSize > 0); 00195 n->Store = _slang_new_ir_storage(PROGRAM_TEMPORARY, -1, defaultSize); 00196 } 00197 00198 /* now allocate actual register(s). I.e. set n->Store->Index >= 0 */ 00199 if (n->Store->Index < 0) { 00200 if (!_slang_alloc_temp(emitInfo->vt, n->Store)) { 00201 slang_info_log_error(emitInfo->log, 00202 "Ran out of registers, too many temporaries"); 00203 _slang_free(n->Store); 00204 n->Store = NULL; 00205 return GL_FALSE; 00206 } 00207 } 00208 return GL_TRUE; 00209 } 00210 00211 00216 static void 00217 free_node_storage(slang_var_table *vt, slang_ir_node *n) 00218 { 00219 if (n->Store->File == PROGRAM_TEMPORARY && 00220 n->Store->Index >= 0 && 00221 n->Opcode != IR_SWIZZLE) { 00222 if (_slang_is_temp(vt, n->Store)) { 00223 _slang_free_temp(vt, n->Store); 00224 n->Store->Index = -1; 00225 n->Store = NULL; /* XXX this may not be needed */ 00226 } 00227 } 00228 } 00229 00230 00235 static GLboolean 00236 alloc_local_temp(slang_emit_info *emitInfo, slang_ir_storage *temp, GLint size) 00237 { 00238 assert(size >= 1); 00239 assert(size <= 4); 00240 _mesa_bzero(temp, sizeof(*temp)); 00241 temp->Size = size; 00242 temp->File = PROGRAM_TEMPORARY; 00243 temp->Index = -1; 00244 return _slang_alloc_temp(emitInfo->vt, temp); 00245 } 00246 00247 00253 static GLuint 00254 fix_swizzle(GLuint swizzle) 00255 { 00256 GLuint c0 = GET_SWZ(swizzle, 0), 00257 c1 = GET_SWZ(swizzle, 1), 00258 c2 = GET_SWZ(swizzle, 2), 00259 c3 = GET_SWZ(swizzle, 3); 00260 if (c1 == SWIZZLE_NIL && c2 == SWIZZLE_NIL && c3 == SWIZZLE_NIL) { 00261 /* smear first component across all positions */ 00262 c1 = c2 = c3 = c0; 00263 } 00264 else { 00265 /* insert default swizzle components */ 00266 if (c0 == SWIZZLE_NIL) 00267 c0 = SWIZZLE_X; 00268 if (c1 == SWIZZLE_NIL) 00269 c1 = SWIZZLE_Y; 00270 if (c2 == SWIZZLE_NIL) 00271 c2 = SWIZZLE_Z; 00272 if (c3 == SWIZZLE_NIL) 00273 c3 = SWIZZLE_W; 00274 } 00275 return MAKE_SWIZZLE4(c0, c1, c2, c3); 00276 } 00277 00278 00279 00283 static void 00284 storage_to_dst_reg(struct prog_dst_register *dst, const slang_ir_storage *st) 00285 { 00286 const GLboolean relAddr = st->RelAddr; 00287 const GLint size = st->Size; 00288 GLint index = st->Index; 00289 GLuint swizzle = st->Swizzle; 00290 00291 assert(index >= 0); 00292 /* if this is storage relative to some parent storage, walk up the tree */ 00293 while (st->Parent) { 00294 st = st->Parent; 00295 assert(st->Index >= 0); 00296 index += st->Index; 00297 swizzle = _slang_swizzle_swizzle(st->Swizzle, swizzle); 00298 } 00299 00300 assert(st->File != PROGRAM_UNDEFINED); 00301 dst->File = st->File; 00302 00303 assert(index >= 0); 00304 dst->Index = index; 00305 00306 assert(size >= 1); 00307 assert(size <= 4); 00308 00309 if (swizzle != SWIZZLE_XYZW) { 00310 dst->WriteMask = swizzle_to_writemask(swizzle); 00311 } 00312 else { 00313 switch (size) { 00314 case 1: 00315 dst->WriteMask = WRITEMASK_X << GET_SWZ(st->Swizzle, 0); 00316 break; 00317 case 2: 00318 dst->WriteMask = WRITEMASK_XY; 00319 break; 00320 case 3: 00321 dst->WriteMask = WRITEMASK_XYZ; 00322 break; 00323 case 4: 00324 dst->WriteMask = WRITEMASK_XYZW; 00325 break; 00326 default: 00327 ; /* error would have been caught above */ 00328 } 00329 } 00330 00331 dst->RelAddr = relAddr; 00332 } 00333 00334 00338 static void 00339 storage_to_src_reg(struct prog_src_register *src, const slang_ir_storage *st) 00340 { 00341 const GLboolean relAddr = st->RelAddr; 00342 GLint index = st->Index; 00343 GLuint swizzle = st->Swizzle; 00344 00345 /* if this is storage relative to some parent storage, walk up the tree */ 00346 assert(index >= 0); 00347 while (st->Parent) { 00348 st = st->Parent; 00349 if (st->Index < 0) { 00350 /* an error should have been reported already */ 00351 return; 00352 } 00353 assert(st->Index >= 0); 00354 index += st->Index; 00355 swizzle = _slang_swizzle_swizzle(fix_swizzle(st->Swizzle), swizzle); 00356 } 00357 00358 assert(st->File >= 0); 00359 #if 1 /* XXX temporary */ 00360 if (st->File == PROGRAM_UNDEFINED) { 00361 slang_ir_storage *st0 = (slang_ir_storage *) st; 00362 st0->File = PROGRAM_TEMPORARY; 00363 } 00364 #endif 00365 assert(st->File < PROGRAM_UNDEFINED); 00366 src->File = st->File; 00367 00368 assert(index >= 0); 00369 src->Index = index; 00370 00371 swizzle = fix_swizzle(swizzle); 00372 assert(GET_SWZ(swizzle, 0) <= SWIZZLE_W); 00373 assert(GET_SWZ(swizzle, 1) <= SWIZZLE_W); 00374 assert(GET_SWZ(swizzle, 2) <= SWIZZLE_W); 00375 assert(GET_SWZ(swizzle, 3) <= SWIZZLE_W); 00376 src->Swizzle = swizzle; 00377 00378 src->RelAddr = relAddr; 00379 } 00380 00381 00382 /* 00383 * Setup storage pointing to a scalar constant/literal. 00384 */ 00385 static void 00386 constant_to_storage(slang_emit_info *emitInfo, 00387 GLfloat val, 00388 slang_ir_storage *store) 00389 { 00390 GLuint swizzle; 00391 GLint reg; 00392 GLfloat value[4]; 00393 00394 value[0] = val; 00395 reg = _mesa_add_unnamed_constant(emitInfo->prog->Parameters, 00396 value, 1, &swizzle); 00397 00398 memset(store, 0, sizeof(*store)); 00399 store->File = PROGRAM_CONSTANT; 00400 store->Index = reg; 00401 store->Swizzle = swizzle; 00402 } 00403 00404 00411 static struct prog_instruction * 00412 new_instruction(slang_emit_info *emitInfo, gl_inst_opcode opcode) 00413 { 00414 struct gl_program *prog = emitInfo->prog; 00415 struct prog_instruction *inst; 00416 00417 #if 0 00418 /* print prev inst */ 00419 if (prog->NumInstructions > 0) { 00420 _mesa_print_instruction(prog->Instructions + prog->NumInstructions - 1); 00421 } 00422 #endif 00423 assert(prog->NumInstructions <= emitInfo->MaxInstructions); 00424 00425 if (prog->NumInstructions == emitInfo->MaxInstructions) { 00426 /* grow the instruction buffer */ 00427 emitInfo->MaxInstructions += 20; 00428 prog->Instructions = 00429 _mesa_realloc_instructions(prog->Instructions, 00430 prog->NumInstructions, 00431 emitInfo->MaxInstructions); 00432 } 00433 00434 inst = prog->Instructions + prog->NumInstructions; 00435 prog->NumInstructions++; 00436 _mesa_init_instructions(inst, 1); 00437 inst->Opcode = opcode; 00438 inst->BranchTarget = -1; /* invalid */ 00439 /* 00440 printf("New inst %d: %p %s\n", prog->NumInstructions-1,(void*)inst, 00441 _mesa_opcode_string(inst->Opcode)); 00442 */ 00443 return inst; 00444 } 00445 00446 00447 static struct prog_instruction * 00448 emit_arl_load(slang_emit_info *emitInfo, 00449 enum register_file file, GLint index, GLuint swizzle) 00450 { 00451 struct prog_instruction *inst = new_instruction(emitInfo, OPCODE_ARL); 00452 inst->SrcReg[0].File = file; 00453 inst->SrcReg[0].Index = index; 00454 inst->SrcReg[0].Swizzle = fix_swizzle(swizzle); 00455 inst->DstReg.File = PROGRAM_ADDRESS; 00456 inst->DstReg.Index = 0; 00457 inst->DstReg.WriteMask = WRITEMASK_X; 00458 return inst; 00459 } 00460 00461 00470 static struct prog_instruction * 00471 emit_instruction(slang_emit_info *emitInfo, 00472 gl_inst_opcode opcode, 00473 const slang_ir_storage *dst, 00474 const slang_ir_storage *src0, 00475 const slang_ir_storage *src1, 00476 const slang_ir_storage *src2) 00477 { 00478 struct prog_instruction *inst; 00479 GLuint numIndirect = 0; 00480 const slang_ir_storage *src[3]; 00481 slang_ir_storage newSrc[3], newDst; 00482 GLuint i; 00483 GLboolean isTemp[3]; 00484 00485 isTemp[0] = isTemp[1] = isTemp[2] = GL_FALSE; 00486 00487 src[0] = src0; 00488 src[1] = src1; 00489 src[2] = src2; 00490 00491 /* count up how many operands are indirect loads */ 00492 for (i = 0; i < 3; i++) { 00493 if (src[i] && src[i]->IsIndirect) 00494 numIndirect++; 00495 } 00496 if (dst && dst->IsIndirect) 00497 numIndirect++; 00498 00499 /* Take special steps for indirect register loads. 00500 * If we had multiple address registers this would be simpler. 00501 * For example, this GLSL code: 00502 * x[i] = y[j] + z[k]; 00503 * would translate into something like: 00504 * ARL ADDR.x, i; 00505 * ARL ADDR.y, j; 00506 * ARL ADDR.z, k; 00507 * ADD TEMP[ADDR.x+5], TEMP[ADDR.y+9], TEMP[ADDR.z+4]; 00508 * But since we currently only have one address register we have to do this: 00509 * ARL ADDR.x, i; 00510 * MOV t1, TEMP[ADDR.x+9]; 00511 * ARL ADDR.x, j; 00512 * MOV t2, TEMP[ADDR.x+4]; 00513 * ARL ADDR.x, k; 00514 * ADD TEMP[ADDR.x+5], t1, t2; 00515 * The code here figures this out... 00516 */ 00517 if (numIndirect > 0) { 00518 for (i = 0; i < 3; i++) { 00519 if (src[i] && src[i]->IsIndirect) { 00520 /* load the ARL register with the indirect register */ 00521 emit_arl_load(emitInfo, 00522 src[i]->IndirectFile, 00523 src[i]->IndirectIndex, 00524 src[i]->IndirectSwizzle); 00525 00526 if (numIndirect > 1) { 00527 /* Need to load src[i] into a temporary register */ 00528 slang_ir_storage srcRelAddr; 00529 alloc_local_temp(emitInfo, &newSrc[i], src[i]->Size); 00530 isTemp[i] = GL_TRUE; 00531 00532 /* set RelAddr flag on src register */ 00533 srcRelAddr = *src[i]; 00534 srcRelAddr.RelAddr = GL_TRUE; 00535 srcRelAddr.IsIndirect = GL_FALSE; /* not really needed */ 00536 00537 /* MOV newSrc, srcRelAddr; */ 00538 inst = emit_instruction(emitInfo, 00539 OPCODE_MOV, 00540 &newSrc[i], 00541 &srcRelAddr, 00542 NULL, 00543 NULL); 00544 00545 src[i] = &newSrc[i]; 00546 } 00547 else { 00548 /* just rewrite the src[i] storage to be ARL-relative */ 00549 newSrc[i] = *src[i]; 00550 newSrc[i].RelAddr = GL_TRUE; 00551 newSrc[i].IsIndirect = GL_FALSE; /* not really needed */ 00552 src[i] = &newSrc[i]; 00553 } 00554 } 00555 } 00556 } 00557 00558 /* Take special steps for indirect dest register write */ 00559 if (dst && dst->IsIndirect) { 00560 /* load the ARL register with the indirect register */ 00561 emit_arl_load(emitInfo, 00562 dst->IndirectFile, 00563 dst->IndirectIndex, 00564 dst->IndirectSwizzle); 00565 newDst = *dst; 00566 newDst.RelAddr = GL_TRUE; 00567 newDst.IsIndirect = GL_FALSE; 00568 dst = &newDst; 00569 } 00570 00571 /* OK, emit the instruction and its dst, src regs */ 00572 inst = new_instruction(emitInfo, opcode); 00573 if (!inst) 00574 return NULL; 00575 00576 if (dst) 00577 storage_to_dst_reg(&inst->DstReg, dst); 00578 00579 for (i = 0; i < 3; i++) { 00580 if (src[i]) 00581 storage_to_src_reg(&inst->SrcReg[i], src[i]); 00582 } 00583 00584 /* Free any temp registers that we allocated above */ 00585 for (i = 0; i < 3; i++) { 00586 if (isTemp[i]) 00587 _slang_free_temp(emitInfo->vt, &newSrc[i]); 00588 } 00589 00590 return inst; 00591 } 00592 00593 00594 00598 static void 00599 inst_comment(struct prog_instruction *inst, const char *comment) 00600 { 00601 if (inst) 00602 inst->Comment = _mesa_strdup(comment); 00603 } 00604 00605 00606 00610 static struct prog_instruction * 00611 prev_instruction(slang_emit_info *emitInfo) 00612 { 00613 struct gl_program *prog = emitInfo->prog; 00614 if (prog->NumInstructions == 0) 00615 return NULL; 00616 else 00617 return prog->Instructions + prog->NumInstructions - 1; 00618 } 00619 00620 00621 static struct prog_instruction * 00622 emit(slang_emit_info *emitInfo, slang_ir_node *n); 00623 00624 00628 static char * 00629 storage_annotation(const slang_ir_node *n, const struct gl_program *prog) 00630 { 00631 #if ANNOTATE 00632 const slang_ir_storage *st = n->Store; 00633 static char s[100] = ""; 00634 00635 if (!st) 00636 return _mesa_strdup(""); 00637 00638 switch (st->File) { 00639 case PROGRAM_CONSTANT: 00640 if (st->Index >= 0) { 00641 const GLfloat *val = prog->Parameters->ParameterValues[st->Index]; 00642 if (st->Swizzle == SWIZZLE_NOOP) 00643 sprintf(s, "{%g, %g, %g, %g}", val[0], val[1], val[2], val[3]); 00644 else { 00645 sprintf(s, "%g", val[GET_SWZ(st->Swizzle, 0)]); 00646 } 00647 } 00648 break; 00649 case PROGRAM_TEMPORARY: 00650 if (n->Var) 00651 sprintf(s, "%s", (char *) n->Var->a_name); 00652 else 00653 sprintf(s, "t[%d]", st->Index); 00654 break; 00655 case PROGRAM_STATE_VAR: 00656 case PROGRAM_UNIFORM: 00657 sprintf(s, "%s", prog->Parameters->Parameters[st->Index].Name); 00658 break; 00659 case PROGRAM_VARYING: 00660 sprintf(s, "%s", prog->Varying->Parameters[st->Index].Name); 00661 break; 00662 case PROGRAM_INPUT: 00663 sprintf(s, "input[%d]", st->Index); 00664 break; 00665 case PROGRAM_OUTPUT: 00666 sprintf(s, "output[%d]", st->Index); 00667 break; 00668 default: 00669 s[0] = 0; 00670 } 00671 return _mesa_strdup(s); 00672 #else 00673 return NULL; 00674 #endif 00675 } 00676 00677 00681 static char * 00682 instruction_annotation(gl_inst_opcode opcode, char *dstAnnot, 00683 char *srcAnnot0, char *srcAnnot1, char *srcAnnot2) 00684 { 00685 #if ANNOTATE 00686 const char *operator; 00687 char *s; 00688 int len = 50; 00689 00690 if (dstAnnot) 00691 len += strlen(dstAnnot); 00692 else 00693 dstAnnot = _mesa_strdup(""); 00694 00695 if (srcAnnot0) 00696 len += strlen(srcAnnot0); 00697 else 00698 srcAnnot0 = _mesa_strdup(""); 00699 00700 if (srcAnnot1) 00701 len += strlen(srcAnnot1); 00702 else 00703 srcAnnot1 = _mesa_strdup(""); 00704 00705 if (srcAnnot2) 00706 len += strlen(srcAnnot2); 00707 else 00708 srcAnnot2 = _mesa_strdup(""); 00709 00710 switch (opcode) { 00711 case OPCODE_ADD: 00712 operator = "+"; 00713 break; 00714 case OPCODE_SUB: 00715 operator = "-"; 00716 break; 00717 case OPCODE_MUL: 00718 operator = "*"; 00719 break; 00720 case OPCODE_DP2: 00721 operator = "DP2"; 00722 break; 00723 case OPCODE_DP3: 00724 operator = "DP3"; 00725 break; 00726 case OPCODE_DP4: 00727 operator = "DP4"; 00728 break; 00729 case OPCODE_XPD: 00730 operator = "XPD"; 00731 break; 00732 case OPCODE_RSQ: 00733 operator = "RSQ"; 00734 break; 00735 case OPCODE_SGT: 00736 operator = ">"; 00737 break; 00738 default: 00739 operator = ","; 00740 } 00741 00742 s = (char *) malloc(len); 00743 sprintf(s, "%s = %s %s %s %s", dstAnnot, 00744 srcAnnot0, operator, srcAnnot1, srcAnnot2); 00745 assert(_mesa_strlen(s) < len); 00746 00747 free(dstAnnot); 00748 free(srcAnnot0); 00749 free(srcAnnot1); 00750 free(srcAnnot2); 00751 00752 return s; 00753 #else 00754 return NULL; 00755 #endif 00756 } 00757 00758 00762 static struct prog_instruction * 00763 emit_comment(slang_emit_info *emitInfo, const char *comment) 00764 { 00765 struct prog_instruction *inst = new_instruction(emitInfo, OPCODE_NOP); 00766 inst_comment(inst, comment); 00767 return inst; 00768 } 00769 00770 00775 static struct prog_instruction * 00776 emit_arith(slang_emit_info *emitInfo, slang_ir_node *n) 00777 { 00778 const slang_ir_info *info = _slang_ir_info(n->Opcode); 00779 struct prog_instruction *inst; 00780 GLuint i; 00781 00782 assert(info); 00783 assert(info->InstOpcode != OPCODE_NOP); 00784 00785 #if PEEPHOLE_OPTIMIZATIONS 00786 /* Look for MAD opportunity */ 00787 if (info->NumParams == 2 && 00788 n->Opcode == IR_ADD && n->Children[0]->Opcode == IR_MUL) { 00789 /* found pattern IR_ADD(IR_MUL(A, B), C) */ 00790 emit(emitInfo, n->Children[0]->Children[0]); /* A */ 00791 emit(emitInfo, n->Children[0]->Children[1]); /* B */ 00792 emit(emitInfo, n->Children[1]); /* C */ 00793 alloc_node_storage(emitInfo, n, -1); /* dest */ 00794 00795 inst = emit_instruction(emitInfo, 00796 OPCODE_MAD, 00797 n->Store, 00798 n->Children[0]->Children[0]->Store, 00799 n->Children[0]->Children[1]->Store, 00800 n->Children[1]->Store); 00801 00802 free_node_storage(emitInfo->vt, n->Children[0]->Children[0]); 00803 free_node_storage(emitInfo->vt, n->Children[0]->Children[1]); 00804 free_node_storage(emitInfo->vt, n->Children[1]); 00805 return inst; 00806 } 00807 00808 if (info->NumParams == 2 && 00809 n->Opcode == IR_ADD && n->Children[1]->Opcode == IR_MUL) { 00810 /* found pattern IR_ADD(A, IR_MUL(B, C)) */ 00811 emit(emitInfo, n->Children[0]); /* A */ 00812 emit(emitInfo, n->Children[1]->Children[0]); /* B */ 00813 emit(emitInfo, n->Children[1]->Children[1]); /* C */ 00814 alloc_node_storage(emitInfo, n, -1); /* dest */ 00815 00816 inst = emit_instruction(emitInfo, 00817 OPCODE_MAD, 00818 n->Store, 00819 n->Children[1]->Children[0]->Store, 00820 n->Children[1]->Children[1]->Store, 00821 n->Children[0]->Store); 00822 00823 free_node_storage(emitInfo->vt, n->Children[1]->Children[0]); 00824 free_node_storage(emitInfo->vt, n->Children[1]->Children[1]); 00825 free_node_storage(emitInfo->vt, n->Children[0]); 00826 return inst; 00827 } 00828 #endif 00829 00830 /* gen code for children, may involve temp allocation */ 00831 for (i = 0; i < info->NumParams; i++) { 00832 emit(emitInfo, n->Children[i]); 00833 if (!n->Children[i] || !n->Children[i]->Store) { 00834 /* error recovery */ 00835 return NULL; 00836 } 00837 } 00838 00839 /* result storage */ 00840 alloc_node_storage(emitInfo, n, -1); 00841 00842 inst = emit_instruction(emitInfo, 00843 info->InstOpcode, 00844 n->Store, /* dest */ 00845 (info->NumParams > 0 ? n->Children[0]->Store : NULL), 00846 (info->NumParams > 1 ? n->Children[1]->Store : NULL), 00847 (info->NumParams > 2 ? n->Children[2]->Store : NULL) 00848 ); 00849 00850 /* free temps */ 00851 for (i = 0; i < info->NumParams; i++) 00852 free_node_storage(emitInfo->vt, n->Children[i]); 00853 00854 return inst; 00855 } 00856 00857 00862 static struct prog_instruction * 00863 emit_compare(slang_emit_info *emitInfo, slang_ir_node *n) 00864 { 00865 struct prog_instruction *inst = NULL; 00866 GLint size; 00867 00868 assert(n->Opcode == IR_EQUAL || n->Opcode == IR_NOTEQUAL); 00869 00870 /* gen code for children */ 00871 emit(emitInfo, n->Children[0]); 00872 emit(emitInfo, n->Children[1]); 00873 00874 if (n->Children[0]->Store->Size != n->Children[1]->Store->Size) { 00875 slang_info_log_error(emitInfo->log, "invalid operands to == or !="); 00876 n->Store = NULL; 00877 return NULL; 00878 } 00879 00880 /* final result is 1 bool */ 00881 if (!alloc_node_storage(emitInfo, n, 1)) 00882 return NULL; 00883 00884 size = n->Children[0]->Store->Size; 00885 00886 if (size == 1) { 00887 gl_inst_opcode opcode = n->Opcode == IR_EQUAL ? OPCODE_SEQ : OPCODE_SNE; 00888 inst = emit_instruction(emitInfo, 00889 opcode, 00890 n->Store, /* dest */ 00891 n->Children[0]->Store, 00892 n->Children[1]->Store, 00893 NULL); 00894 } 00895 else if (size <= 4) { 00896 /* compare two vectors. 00897 * Unfortunately, there's no instruction to compare vectors and 00898 * return a scalar result. Do it with some compare and dot product 00899 * instructions... 00900 */ 00901 GLuint swizzle; 00902 gl_inst_opcode dotOp; 00903 slang_ir_storage tempStore; 00904 00905 if (!alloc_local_temp(emitInfo, &tempStore, 4)) { 00906 n->Store = NULL; 00907 return NULL; 00908 /* out of temps */ 00909 } 00910 00911 if (size == 4) { 00912 dotOp = OPCODE_DP4; 00913 swizzle = SWIZZLE_XYZW; 00914 } 00915 else if (size == 3) { 00916 dotOp = OPCODE_DP3; 00917 swizzle = SWIZZLE_XYZW; 00918 } 00919 else { 00920 assert(size == 2); 00921 dotOp = OPCODE_DP3; /* XXX use OPCODE_DP2 eventually */ 00922 swizzle = MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Y, SWIZZLE_Y); 00923 } 00924 00925 /* Compute inequality (temp = (A != B)) */ 00926 inst = emit_instruction(emitInfo, 00927 OPCODE_SNE, 00928 &tempStore, 00929 n->Children[0]->Store, 00930 n->Children[1]->Store, 00931 NULL); 00932 inst_comment(inst, "Compare values"); 00933 00934 /* Compute val = DOT(temp, temp) (reduction) */ 00935 inst = emit_instruction(emitInfo, 00936 dotOp, 00937 n->Store, 00938 &tempStore, 00939 &tempStore, 00940 NULL); 00941 inst->SrcReg[0].Swizzle = inst->SrcReg[1].Swizzle = swizzle; /*override*/ 00942 inst_comment(inst, "Reduce vec to bool"); 00943 00944 _slang_free_temp(emitInfo->vt, &tempStore); /* free temp */ 00945 00946 if (n->Opcode == IR_EQUAL) { 00947 /* compute val = !val.x with SEQ val, val, 0; */ 00948 slang_ir_storage zero; 00949 constant_to_storage(emitInfo, 0.0, &zero); 00950 inst = emit_instruction(emitInfo, 00951 OPCODE_SEQ, 00952 n->Store, /* dest */ 00953 n->Store, 00954 &zero, 00955 NULL); 00956 inst_comment(inst, "Invert true/false"); 00957 } 00958 } 00959 else { 00960 /* size > 4, struct or array compare. 00961 * XXX this won't work reliably for structs with padding!! 00962 */ 00963 GLint i, num = (n->Children[0]->Store->Size + 3) / 4; 00964 slang_ir_storage accTemp, sneTemp; 00965 00966 if (!alloc_local_temp(emitInfo, &accTemp, 4)) 00967 return NULL; 00968 00969 if (!alloc_local_temp(emitInfo, &sneTemp, 4)) 00970 return NULL; 00971 00972 for (i = 0; i < num; i++) { 00973 slang_ir_storage srcStore0 = *n->Children[0]->Store; 00974 slang_ir_storage srcStore1 = *n->Children[1]->Store; 00975 srcStore0.Index += i; 00976 srcStore1.Index += i; 00977 00978 if (i == 0) { 00979 /* SNE accTemp, left[i], right[i] */ 00980 inst = emit_instruction(emitInfo, OPCODE_SNE, 00981 &accTemp, /* dest */ 00982 &srcStore0, 00983 &srcStore1, 00984 NULL); 00985 inst_comment(inst, "Begin struct/array comparison"); 00986 } 00987 else { 00988 /* SNE sneTemp, left[i], right[i] */ 00989 inst = emit_instruction(emitInfo, OPCODE_SNE, 00990 &sneTemp, /* dest */ 00991 &srcStore0, 00992 &srcStore1, 00993 NULL); 00994 /* ADD accTemp, accTemp, sneTemp; # like logical-OR */ 00995 inst = emit_instruction(emitInfo, OPCODE_ADD, 00996 &accTemp, /* dest */ 00997 &accTemp, 00998 &sneTemp, 00999 NULL); 01000 } 01001 } 01002 01003 /* compute accTemp.x || accTemp.y || accTemp.z || accTemp.w with DOT4 */ 01004 inst = emit_instruction(emitInfo, OPCODE_DP4, 01005 n->Store, 01006 &accTemp, 01007 &accTemp, 01008 NULL); 01009 inst_comment(inst, "End struct/array comparison"); 01010 01011 if (n->Opcode == IR_EQUAL) { 01012 /* compute tmp.x = !tmp.x via tmp.x = (tmp.x == 0) */ 01013 slang_ir_storage zero; 01014 constant_to_storage(emitInfo, 0.0, &zero); 01015 inst = emit_instruction(emitInfo, OPCODE_SEQ, 01016 n->Store, /* dest */ 01017 n->Store, 01018 &zero, 01019 NULL); 01020 inst_comment(inst, "Invert true/false"); 01021 } 01022 01023 _slang_free_temp(emitInfo->vt, &accTemp); 01024 _slang_free_temp(emitInfo->vt, &sneTemp); 01025 } 01026 01027 /* free temps */ 01028 free_node_storage(emitInfo->vt, n->Children[0]); 01029 free_node_storage(emitInfo->vt, n->Children[1]); 01030 01031 return inst; 01032 } 01033 01034 01035 01039 static struct prog_instruction * 01040 emit_clamp(slang_emit_info *emitInfo, slang_ir_node *n) 01041 { 01042 struct prog_instruction *inst; 01043 slang_ir_node tmpNode; 01044 01045 assert(n->Opcode == IR_CLAMP); 01046 /* ch[0] = value 01047 * ch[1] = min limit 01048 * ch[2] = max limit 01049 */ 01050 01051 inst = emit(emitInfo, n->Children[0]); 01052 01053 /* If lower limit == 0.0 and upper limit == 1.0, 01054 * set prev instruction's SaturateMode field to SATURATE_ZERO_ONE. 01055 * Else, 01056 * emit OPCODE_MIN, OPCODE_MAX sequence. 01057 */ 01058 #if 0 01059 /* XXX this isn't quite finished yet */ 01060 if (n->Children[1]->Opcode == IR_FLOAT && 01061 n->Children[1]->Value[0] == 0.0 && 01062 n->Children[1]->Value[1] == 0.0 && 01063 n->Children[1]->Value[2] == 0.0 && 01064 n->Children[1]->Value[3] == 0.0 && 01065 n->Children[2]->Opcode == IR_FLOAT && 01066 n->Children[2]->Value[0] == 1.0 && 01067 n->Children[2]->Value[1] == 1.0 && 01068 n->Children[2]->Value[2] == 1.0 && 01069 n->Children[2]->Value[3] == 1.0) { 01070 if (!inst) { 01071 inst = prev_instruction(prog); 01072 } 01073 if (inst && inst->Opcode != OPCODE_NOP) { 01074 /* and prev instruction's DstReg matches n->Children[0]->Store */ 01075 inst->SaturateMode = SATURATE_ZERO_ONE; 01076 n->Store = n->Children[0]->Store; 01077 return inst; 01078 } 01079 } 01080 #endif 01081 01082 if (!alloc_node_storage(emitInfo, n, n->Children[0]->Store->Size)) 01083 return NULL; 01084 01085 emit(emitInfo, n->Children[1]); 01086 emit(emitInfo, n->Children[2]); 01087 01088 /* Some GPUs don't allow reading from output registers. So if the 01089 * dest for this clamp() is an output reg, we can't use that reg for 01090 * the intermediate result. Use a temp register instead. 01091 */ 01092 _mesa_bzero(&tmpNode, sizeof(tmpNode)); 01093 alloc_node_storage(emitInfo, &tmpNode, n->Store->Size); 01094 01095 /* tmp = max(ch[0], ch[1]) */ 01096 inst = emit_instruction(emitInfo, OPCODE_MAX, 01097 tmpNode.Store, /* dest */ 01098 n->Children[0]->Store, 01099 n->Children[1]->Store, 01100 NULL); 01101 01102 /* n->dest = min(tmp, ch[2]) */ 01103 inst = emit_instruction(emitInfo, OPCODE_MIN, 01104 n->Store, /* dest */ 01105 tmpNode.Store, 01106 n->Children[2]->Store, 01107 NULL); 01108 01109 free_node_storage(emitInfo->vt, &tmpNode); 01110 01111 return inst; 01112 } 01113 01114 01115 static struct prog_instruction * 01116 emit_negation(slang_emit_info *emitInfo, slang_ir_node *n) 01117 { 01118 /* Implement as MOV dst, -src; */ 01119 /* XXX we could look at the previous instruction and in some circumstances 01120 * modify it to accomplish the negation. 01121 */ 01122 struct prog_instruction *inst; 01123 01124 emit(emitInfo, n->Children[0]); 01125 01126 if (!alloc_node_storage(emitInfo, n, n->Children[0]->Store->Size)) 01127 return NULL; 01128 01129 inst = emit_instruction(emitInfo, 01130 OPCODE_MOV, 01131 n->Store, /* dest */ 01132 n->Children[0]->Store, 01133 NULL, 01134 NULL); 01135 inst->SrcReg[0].NegateBase = NEGATE_XYZW; 01136 return inst; 01137 } 01138 01139 01140 static struct prog_instruction * 01141 emit_label(slang_emit_info *emitInfo, const slang_ir_node *n) 01142 { 01143 assert(n->Label); 01144 #if 0 01145 /* XXX this fails in loop tail code - investigate someday */ 01146 assert(_slang_label_get_location(n->Label) < 0); 01147 _slang_label_set_location(n->Label, emitInfo->prog->NumInstructions, 01148 emitInfo->prog); 01149 #else 01150 if (_slang_label_get_location(n->Label) < 0) 01151 _slang_label_set_location(n->Label, emitInfo->prog->NumInstructions, 01152 emitInfo->prog); 01153 #endif 01154 return NULL; 01155 } 01156 01157 01163 static struct prog_instruction * 01164 emit_fcall(slang_emit_info *emitInfo, slang_ir_node *n) 01165 { 01166 struct gl_program *progSave; 01167 struct prog_instruction *inst; 01168 GLuint subroutineId; 01169 GLuint maxInstSave; 01170 01171 assert(n->Opcode == IR_CALL); 01172 assert(n->Label); 01173 01174 /* save/push cur program */ 01175 maxInstSave = emitInfo->MaxInstructions; 01176 progSave = emitInfo->prog; 01177 01178 emitInfo->prog = new_subroutine(emitInfo, &subroutineId); 01179 emitInfo->MaxInstructions = emitInfo->prog->NumInstructions; 01180 01181 _slang_label_set_location(n->Label, emitInfo->prog->NumInstructions, 01182 emitInfo->prog); 01183 01184 if (emitInfo->EmitBeginEndSub) { 01185 /* BGNSUB isn't a real instruction. 01186 * We require a label (i.e. "foobar:") though, if we're going to 01187 * print the program in the NV format. The BNGSUB instruction is 01188 * really just a NOP to attach the label to. 01189 */ 01190 inst = new_instruction(emitInfo, OPCODE_BGNSUB); 01191 inst_comment(inst, n->Label->Name); 01192 } 01193 01194 /* body of function: */ 01195 emit(emitInfo, n->Children[0]); 01196 n->Store = n->Children[0]->Store; 01197 01198 /* add RET instruction now, if needed */ 01199 inst = prev_instruction(emitInfo); 01200 if (inst && inst->Opcode != OPCODE_RET) { 01201 inst = new_instruction(emitInfo, OPCODE_RET); 01202 } 01203 01204 if (emitInfo->EmitBeginEndSub) { 01205 inst = new_instruction(emitInfo, OPCODE_ENDSUB); 01206 inst_comment(inst, n->Label->Name); 01207 } 01208 01209 /* pop/restore cur program */ 01210 emitInfo->prog = progSave; 01211 emitInfo->MaxInstructions = maxInstSave; 01212 01213 /* emit the function call */ 01214 inst = new_instruction(emitInfo, OPCODE_CAL); 01215 /* The branch target is just the subroutine number (changed later) */ 01216 inst->BranchTarget = subroutineId; 01217 inst_comment(inst, n->Label->Name); 01218 assert(inst->BranchTarget >= 0); 01219 01220 return inst; 01221 } 01222 01223 01227 static struct prog_instruction * 01228 emit_return(slang_emit_info *emitInfo, slang_ir_node *n) 01229 { 01230 struct prog_instruction *inst; 01231 assert(n); 01232 assert(n->Opcode == IR_RETURN); 01233 assert(n->Label); 01234 inst = new_instruction(emitInfo, OPCODE_RET); 01235 inst->DstReg.CondMask = COND_TR; /* always return */ 01236 return inst; 01237 } 01238 01239 01240 static struct prog_instruction * 01241 emit_kill(slang_emit_info *emitInfo) 01242 { 01243 struct gl_fragment_program *fp; 01244 struct prog_instruction *inst; 01245 /* NV-KILL - discard fragment depending on condition code. 01246 * Note that ARB-KILL depends on sign of vector operand. 01247 */ 01248 inst = new_instruction(emitInfo, OPCODE_KIL_NV); 01249 inst->DstReg.CondMask = COND_TR; /* always kill */ 01250 01251 assert(emitInfo->prog->Target == GL_FRAGMENT_PROGRAM_ARB); 01252 fp = (struct gl_fragment_program *) emitInfo->prog; 01253 fp->UsesKill = GL_TRUE; 01254 01255 return inst; 01256 } 01257 01258 01259 static struct prog_instruction * 01260 emit_tex(slang_emit_info *emitInfo, slang_ir_node *n) 01261 { 01262 struct prog_instruction *inst; 01263 gl_inst_opcode opcode; 01264 01265 if (n->Opcode == IR_TEX) { 01266 opcode = OPCODE_TEX; 01267 } 01268 else if (n->Opcode == IR_TEXB) { 01269 opcode = OPCODE_TXB; 01270 } 01271 else { 01272 assert(n->Opcode == IR_TEXP); 01273 opcode = OPCODE_TXP; 01274 } 01275 01276 if (n->Children[0]->Opcode == IR_ELEMENT) { 01277 /* array is the sampler (a uniform which'll indicate the texture unit) */ 01278 assert(n->Children[0]->Children[0]->Store); 01279 assert(n->Children[0]->Children[0]->Store->File == PROGRAM_SAMPLER); 01280 01281 emit(emitInfo, n->Children[0]); 01282 01283 n->Children[0]->Var = n->Children[0]->Children[0]->Var; 01284 } else { 01285 /* this is the sampler (a uniform which'll indicate the texture unit) */ 01286 assert(n->Children[0]->Store); 01287 assert(n->Children[0]->Store->File == PROGRAM_SAMPLER); 01288 } 01289 01290 /* emit code for the texcoord operand */ 01291 (void) emit(emitInfo, n->Children[1]); 01292 01293 /* alloc storage for result of texture fetch */ 01294 if (!alloc_node_storage(emitInfo, n, 4)) 01295 return NULL; 01296 01297 /* emit TEX instruction; Child[1] is the texcoord */ 01298 inst = emit_instruction(emitInfo, 01299 opcode, 01300 n->Store, 01301 n->Children[1]->Store, 01302 NULL, 01303 NULL); 01304 01305 /* Store->Index is the uniform/sampler index */ 01306 assert(n->Children[0]->Store->Index >= 0); 01307 inst->TexSrcUnit = n->Children[0]->Store->Index; 01308 inst->TexSrcTarget = n->Children[0]->Store->TexTarget; 01309 01310 /* mark the sampler as being used */ 01311 _mesa_use_uniform(emitInfo->prog->Parameters, 01312 (char *) n->Children[0]->Var->a_name); 01313 01314 return inst; 01315 } 01316 01317 01321 static struct prog_instruction * 01322 emit_copy(slang_emit_info *emitInfo, slang_ir_node *n) 01323 { 01324 struct prog_instruction *inst; 01325 01326 assert(n->Opcode == IR_COPY); 01327 01328 /* lhs */ 01329 emit(emitInfo, n->Children[0]); 01330 if (!n->Children[0]->Store || n->Children[0]->Store->Index < 0) { 01331 /* an error should have been already recorded */ 01332 return NULL; 01333 } 01334 01335 /* rhs */ 01336 assert(n->Children[1]); 01337 inst = emit(emitInfo, n->Children[1]); 01338 01339 if (!n->Children[1]->Store || n->Children[1]->Store->Index < 0) { 01340 if (!emitInfo->log->text) { 01341 slang_info_log_error(emitInfo->log, "invalid assignment"); 01342 } 01343 return NULL; 01344 } 01345 01346 assert(n->Children[1]->Store->Index >= 0); 01347 01348 /*assert(n->Children[0]->Store->Size == n->Children[1]->Store->Size);*/ 01349 01350 n->Store = n->Children[0]->Store; 01351 01352 if (n->Store->File == PROGRAM_SAMPLER) { 01353 /* no code generated for sampler assignments, 01354 * just copy the sampler index/target at compile time. 01355 */ 01356 n->Store->Index = n->Children[1]->Store->Index; 01357 n->Store->TexTarget = n->Children[1]->Store->TexTarget; 01358 return NULL; 01359 } 01360 01361 #if PEEPHOLE_OPTIMIZATIONS 01362 if (inst && 01363 (n->Children[1]->Opcode != IR_SWIZZLE) && 01364 _slang_is_temp(emitInfo->vt, n->Children[1]->Store) && 01365 (inst->DstReg.File == n->Children[1]->Store->File) && 01366 (inst->DstReg.Index == n->Children[1]->Store->Index) && 01367 !n->Children[0]->Store->IsIndirect && 01368 n->Children[0]->Store->Size <= 4) { 01369 /* Peephole optimization: 01370 * The Right-Hand-Side has its results in a temporary place. 01371 * Modify the RHS (and the prev instruction) to store its results 01372 * in the destination specified by n->Children[0]. 01373 * Then, this MOVE is a no-op. 01374 * Ex: 01375 * MUL tmp, x, y; 01376 * MOV a, tmp; 01377 * becomes: 01378 * MUL a, x, y; 01379 */ 01380 01381 /* fixup the previous instruction (which stored the RHS result) */ 01382 assert(n->Children[0]->Store->Index >= 0); 01383 storage_to_dst_reg(&inst->DstReg, n->Children[0]->Store); 01384 return inst; 01385 } 01386 else 01387 #endif 01388 { 01389 if (n->Children[0]->Store->Size > 4) { 01390 /* move matrix/struct etc (block of registers) */ 01391 slang_ir_storage dstStore = *n->Children[0]->Store; 01392 slang_ir_storage srcStore = *n->Children[1]->Store; 01393 GLint size = srcStore.Size; 01394 ASSERT(n->Children[1]->Store->Swizzle == SWIZZLE_NOOP); 01395 dstStore.Size = 4; 01396 srcStore.Size = 4; 01397 while (size >= 4) { 01398 inst = emit_instruction(emitInfo, OPCODE_MOV, 01399 &dstStore, 01400 &srcStore, 01401 NULL, 01402 NULL); 01403 inst_comment(inst, "IR_COPY block"); 01404 srcStore.Index++; 01405 dstStore.Index++; 01406 size -= 4; 01407 } 01408 } 01409 else { 01410 /* single register move */ 01411 char *srcAnnot, *dstAnnot; 01412 assert(n->Children[0]->Store->Index >= 0); 01413 inst = emit_instruction(emitInfo, OPCODE_MOV, 01414 n->Children[0]->Store, /* dest */ 01415 n->Children[1]->Store, 01416 NULL, 01417 NULL); 01418 dstAnnot = storage_annotation(n->Children[0], emitInfo->prog); 01419 srcAnnot = storage_annotation(n->Children[1], emitInfo->prog); 01420 inst->Comment = instruction_annotation(inst->Opcode, dstAnnot, 01421 srcAnnot, NULL, NULL); 01422 } 01423 free_node_storage(emitInfo->vt, n->Children[1]); 01424 return inst; 01425 } 01426 } 01427 01428 01433 static struct prog_instruction * 01434 emit_cond(slang_emit_info *emitInfo, slang_ir_node *n) 01435 { 01436 struct prog_instruction *inst; 01437 01438 assert(n->Opcode == IR_COND); 01439 01440 if (!n->Children[0]) 01441 return NULL; 01442 01443 /* emit code for the expression */ 01444 inst = emit(emitInfo, n->Children[0]); 01445 01446 if (!n->Children[0]->Store) { 01447 /* error recovery */ 01448 return NULL; 01449 } 01450 01451 assert(n->Children[0]->Store); 01452 /*assert(n->Children[0]->Store->Size == 1);*/ 01453 01454 if (emitInfo->EmitCondCodes) { 01455 if (inst && 01456 n->Children[0]->Store && 01457 inst->DstReg.File == n->Children[0]->Store->File && 01458 inst->DstReg.Index == n->Children[0]->Store->Index) { 01459 /* The previous instruction wrote to the register who's value 01460 * we're testing. Just fix that instruction so that the 01461 * condition codes are computed. 01462 */ 01463 inst->CondUpdate = GL_TRUE; 01464 n->Store = n->Children[0]->Store; 01465 return inst; 01466 } 01467 else { 01468 /* This'll happen for things like "if (i) ..." where no code 01469 * is normally generated for the expression "i". 01470 * Generate a move instruction just to set condition codes. 01471 */ 01472 if (!alloc_node_storage(emitInfo, n, 1)) 01473 return NULL; 01474 inst = emit_instruction(emitInfo, OPCODE_MOV, 01475 n->Store, /* dest */ 01476 n->Children[0]->Store, 01477 NULL, 01478 NULL); 01479 inst->CondUpdate = GL_TRUE; 01480 inst_comment(inst, "COND expr"); 01481 _slang_free_temp(emitInfo->vt, n->Store); 01482 return inst; 01483 } 01484 } 01485 else { 01486 /* No-op: the boolean result of the expression is in a regular reg */ 01487 n->Store = n->Children[0]->Store; 01488 return inst; 01489 } 01490 } 01491 01492 01496 static struct prog_instruction * 01497 emit_not(slang_emit_info *emitInfo, slang_ir_node *n) 01498 { 01499 static const struct { 01500 gl_inst_opcode op, opNot; 01501 } operators[] = { 01502 { OPCODE_SLT, OPCODE_SGE }, 01503 { OPCODE_SLE, OPCODE_SGT }, 01504 { OPCODE_SGT, OPCODE_SLE }, 01505 { OPCODE_SGE, OPCODE_SLT }, 01506 { OPCODE_SEQ, OPCODE_SNE }, 01507 { OPCODE_SNE, OPCODE_SEQ }, 01508 { 0, 0 } 01509 }; 01510 struct prog_instruction *inst; 01511 slang_ir_storage zero; 01512 GLuint i; 01513 01514 /* child expr */ 01515 inst = emit(emitInfo, n->Children[0]); 01516 01517 #if PEEPHOLE_OPTIMIZATIONS 01518 if (inst) { 01519 /* if the prev instruction was a comparison instruction, invert it */ 01520 for (i = 0; operators[i].op; i++) { 01521 if (inst->Opcode == operators[i].op) { 01522 inst->Opcode = operators[i].opNot; 01523 n->Store = n->Children[0]->Store; 01524 return inst; 01525 } 01526 } 01527 } 01528 #endif 01529 01530 /* else, invert using SEQ (v = v == 0) */ 01531 if (!alloc_node_storage(emitInfo, n, n->Children[0]->Store->Size)) 01532 return NULL; 01533 01534 constant_to_storage(emitInfo, 0.0, &zero); 01535 inst = emit_instruction(emitInfo, 01536 OPCODE_SEQ, 01537 n->Store, 01538 n->Children[0]->Store, 01539 &zero, 01540 NULL); 01541 inst_comment(inst, "NOT"); 01542 01543 free_node_storage(emitInfo->vt, n->Children[0]); 01544 01545 return inst; 01546 } 01547 01548 01549 static struct prog_instruction * 01550 emit_if(slang_emit_info *emitInfo, slang_ir_node *n) 01551 { 01552 struct gl_program *prog = emitInfo->prog; 01553 GLuint ifInstLoc, elseInstLoc = 0; 01554 GLuint condWritemask = 0; 01555 01556 /* emit condition expression code */ 01557 { 01558 struct prog_instruction *inst; 01559 inst = emit(emitInfo, n->Children[0]); 01560 if (emitInfo->EmitCondCodes) { 01561 if (!inst) { 01562 /* error recovery */ 01563 return NULL; 01564 } 01565 condWritemask = inst->DstReg.WriteMask; 01566 } 01567 } 01568 01569 if (!n->Children[0]->Store) 01570 return NULL; 01571 01572 #if 0 01573 assert(n->Children[0]->Store->Size == 1); /* a bool! */ 01574 #endif 01575 01576 ifInstLoc = prog->NumInstructions; 01577 if (emitInfo->EmitHighLevelInstructions) { 01578 if (emitInfo->EmitCondCodes) { 01579 /* IF condcode THEN ... */ 01580 struct prog_instruction *ifInst; 01581 ifInst = new_instruction(emitInfo, OPCODE_IF); 01582 ifInst->DstReg.CondMask = COND_NE; /* if cond is non-zero */ 01583 /* only test the cond code (1 of 4) that was updated by the 01584 * previous instruction. 01585 */ 01586 ifInst->DstReg.CondSwizzle = writemask_to_swizzle(condWritemask); 01587 } 01588 else { 01589 /* IF src[0] THEN ... */ 01590 emit_instruction(emitInfo, OPCODE_IF, 01591 NULL, /* dst */ 01592 n->Children[0]->Store, /* op0 */ 01593 NULL, 01594 NULL); 01595 } 01596 } 01597 else { 01598 /* conditional jump to else, or endif */ 01599 struct prog_instruction *ifInst = new_instruction(emitInfo, OPCODE_BRA); 01600 ifInst->DstReg.CondMask = COND_EQ; /* BRA if cond is zero */ 01601 inst_comment(ifInst, "if zero"); 01602 ifInst->DstReg.CondSwizzle = writemask_to_swizzle(condWritemask); 01603 } 01604 01605 /* if body */ 01606 emit(emitInfo, n->Children[1]); 01607 01608 if (n->Children[2]) { 01609 /* have else body */ 01610 elseInstLoc = prog->NumInstructions; 01611 if (emitInfo->EmitHighLevelInstructions) { 01612 (void) new_instruction(emitInfo, OPCODE_ELSE); 01613 } 01614 else { 01615 /* jump to endif instruction */ 01616 struct prog_instruction *inst; 01617 inst = new_instruction(emitInfo, OPCODE_BRA); 01618 inst_comment(inst, "else"); 01619 inst->DstReg.CondMask = COND_TR; /* always branch */ 01620 } 01621 prog->Instructions[ifInstLoc].BranchTarget = prog->NumInstructions; 01622 emit(emitInfo, n->Children[2]); 01623 } 01624 else { 01625 /* no else body */ 01626 prog->Instructions[ifInstLoc].BranchTarget = prog->NumInstructions; 01627 } 01628 01629 if (emitInfo->EmitHighLevelInstructions) { 01630 (void) new_instruction(emitInfo, OPCODE_ENDIF); 01631 } 01632 01633 if (n->Children[2]) { 01634 prog->Instructions[elseInstLoc].BranchTarget = prog->NumInstructions; 01635 } 01636 return NULL; 01637 } 01638 01639 01640 static struct prog_instruction * 01641 emit_loop(slang_emit_info *emitInfo, slang_ir_node *n) 01642 { 01643 struct gl_program *prog = emitInfo->prog; 01644 struct prog_instruction *endInst; 01645 GLuint beginInstLoc, tailInstLoc, endInstLoc; 01646 slang_ir_node *ir; 01647 01648 /* emit OPCODE_BGNLOOP */ 01649 beginInstLoc = prog->NumInstructions; 01650 if (emitInfo->EmitHighLevelInstructions) { 01651 (void) new_instruction(emitInfo, OPCODE_BGNLOOP); 01652 } 01653 01654 /* body */ 01655 emit(emitInfo, n->Children[0]); 01656 01657 /* tail */ 01658 tailInstLoc = prog->NumInstructions; 01659 if (n->Children[1]) { 01660 if (emitInfo->EmitComments) 01661 emit_comment(emitInfo, "Loop tail code:"); 01662 emit(emitInfo, n->Children[1]); 01663 } 01664 01665 endInstLoc = prog->NumInstructions; 01666 if (emitInfo->EmitHighLevelInstructions) { 01667 /* emit OPCODE_ENDLOOP */ 01668 endInst = new_instruction(emitInfo, OPCODE_ENDLOOP); 01669 } 01670 else { 01671 /* emit unconditional BRA-nch */ 01672 endInst = new_instruction(emitInfo, OPCODE_BRA); 01673 endInst->DstReg.CondMask = COND_TR; /* always true */ 01674 } 01675 /* ENDLOOP's BranchTarget points to the BGNLOOP inst */ 01676 endInst->BranchTarget = beginInstLoc; 01677 01678 if (emitInfo->EmitHighLevelInstructions) { 01679 /* BGNLOOP's BranchTarget points to the ENDLOOP inst */ 01680 prog->Instructions[beginInstLoc].BranchTarget = prog->NumInstructions -1; 01681 } 01682 01683 /* Done emitting loop code. Now walk over the loop's linked list of 01684 * BREAK and CONT nodes, filling in their BranchTarget fields (which 01685 * will point to the ENDLOOP+1 or BGNLOOP instructions, respectively). 01686 */ 01687 for (ir = n->List; ir; ir = ir->List) { 01688 struct prog_instruction *inst = prog->Instructions + ir->InstLocation; 01689 assert(inst->BranchTarget < 0); 01690 if (ir->Opcode == IR_BREAK || 01691 ir->Opcode == IR_BREAK_IF_TRUE) { 01692 assert(inst->Opcode == OPCODE_BRK || 01693 inst->Opcode == OPCODE_BRA); 01694 /* go to instruction after end of loop */ 01695 inst->BranchTarget = endInstLoc + 1; 01696 } 01697 else { 01698 assert(ir->Opcode == IR_CONT || 01699 ir->Opcode == IR_CONT_IF_TRUE); 01700 assert(inst->Opcode == OPCODE_CONT || 01701 inst->Opcode == OPCODE_BRA); 01702 /* go to instruction at tail of loop */ 01703 inst->BranchTarget = endInstLoc; 01704 } 01705 } 01706 return NULL; 01707 } 01708 01709 01714 static struct prog_instruction * 01715 emit_cont_break(slang_emit_info *emitInfo, slang_ir_node *n) 01716 { 01717 gl_inst_opcode opcode; 01718 struct prog_instruction *inst; 01719 01720 if (n->Opcode == IR_CONT) { 01721 /* we need to execute the loop's tail code before doing CONT */ 01722 assert(n->Parent); 01723 assert(n->Parent->Opcode == IR_LOOP); 01724 if (n->Parent->Children[1]) { 01725 /* emit tail code */ 01726 if (emitInfo->EmitComments) { 01727 emit_comment(emitInfo, "continue - tail code:"); 01728 } 01729 emit(emitInfo, n->Parent->Children[1]); 01730 } 01731 } 01732 01733 /* opcode selection */ 01734 if (emitInfo->EmitHighLevelInstructions) { 01735 opcode = (n->Opcode == IR_CONT) ? OPCODE_CONT : OPCODE_BRK; 01736 } 01737 else { 01738 opcode = OPCODE_BRA; 01739 } 01740 n->InstLocation = emitInfo->prog->NumInstructions; 01741 inst = new_instruction(emitInfo, opcode); 01742 inst->DstReg.CondMask = COND_TR; /* always true */ 01743 return inst; 01744 } 01745 01746 01751 static struct prog_instruction * 01752 emit_cont_break_if_true(slang_emit_info *emitInfo, slang_ir_node *n) 01753 { 01754 struct prog_instruction *inst; 01755 01756 assert(n->Opcode == IR_CONT_IF_TRUE || 01757 n->Opcode == IR_BREAK_IF_TRUE); 01758 01759 /* evaluate condition expr, setting cond codes */ 01760 inst = emit(emitInfo, n->Children[0]); 01761 if (emitInfo->EmitCondCodes) { 01762 assert(inst); 01763 inst->CondUpdate = GL_TRUE; 01764 } 01765 01766 n->InstLocation = emitInfo->prog->NumInstructions; 01767 01768 /* opcode selection */ 01769 if (emitInfo->EmitHighLevelInstructions) { 01770 const gl_inst_opcode opcode 01771 = (n->Opcode == IR_CONT_IF_TRUE) ? OPCODE_CONT : OPCODE_BRK; 01772 if (emitInfo->EmitCondCodes) { 01773 /* Get the writemask from the previous instruction which set 01774 * the condcodes. Use that writemask as the CondSwizzle. 01775 */ 01776 const GLuint condWritemask = inst->DstReg.WriteMask; 01777 inst = new_instruction(emitInfo, opcode); 01778 inst->DstReg.CondMask = COND_NE; 01779 inst->DstReg.CondSwizzle = writemask_to_swizzle(condWritemask); 01780 return inst; 01781 } 01782 else { 01783 /* IF reg 01784 * BRK/CONT; 01785 * ENDIF 01786 */ 01787 GLint ifInstLoc; 01788 ifInstLoc = emitInfo->prog->NumInstructions; 01789 inst = emit_instruction(emitInfo, OPCODE_IF, 01790 NULL, /* dest */ 01791 n->Children[0]->Store, 01792 NULL, 01793 NULL); 01794 n->InstLocation = emitInfo->prog->NumInstructions; 01795 01796 inst = new_instruction(emitInfo, opcode); 01797 inst = new_instruction(emitInfo, OPCODE_ENDIF); 01798 01799 emitInfo->prog->Instructions[ifInstLoc].BranchTarget 01800 = emitInfo->prog->NumInstructions; 01801 return inst; 01802 } 01803 } 01804 else { 01805 const GLuint condWritemask = inst->DstReg.WriteMask; 01806 assert(emitInfo->EmitCondCodes); 01807 inst = new_instruction(emitInfo, OPCODE_BRA); 01808 inst->DstReg.CondMask = COND_NE; 01809 inst->DstReg.CondSwizzle = writemask_to_swizzle(condWritemask); 01810 return inst; 01811 } 01812 } 01813 01814 01822 static GLuint 01823 swizzle_size(GLuint swizzle) 01824 { 01825 GLuint i; 01826 for (i = 0; i < 4; i++) { 01827 if (GET_SWZ(swizzle, i) == SWIZZLE_NIL) 01828 return i; 01829 } 01830 return 4; 01831 } 01832 01833 01834 static struct prog_instruction * 01835 emit_swizzle(slang_emit_info *emitInfo, slang_ir_node *n) 01836 { 01837 struct prog_instruction *inst; 01838 01839 inst = emit(emitInfo, n->Children[0]); 01840 01841 if (!n->Store->Parent) { 01842 /* this covers a case such as "(b ? p : q).x" */ 01843 n->Store->Parent = n->Children[0]->Store; 01844 assert(n->Store->Parent); 01845 } 01846 01847 { 01848 const GLuint swizzle = n->Store->Swizzle; 01849 /* new storage is parent storage with updated Swizzle + Size fields */ 01850 _slang_copy_ir_storage(n->Store, n->Store->Parent); 01851 /* Apply this node's swizzle to parent's storage */ 01852 n->Store->Swizzle = _slang_swizzle_swizzle(n->Store->Swizzle, swizzle); 01853 /* Update size */ 01854 n->Store->Size = swizzle_size(n->Store->Swizzle); 01855 } 01856 01857 assert(!n->Store->Parent); 01858 assert(n->Store->Index >= 0); 01859 01860 return inst; 01861 } 01862 01863 01869 static struct prog_instruction * 01870 emit_array_element(slang_emit_info *emitInfo, slang_ir_node *n) 01871 { 01872 slang_ir_storage *arrayStore, *indexStore; 01873 const int elemSize = n->Store->Size; /* number of floats */ 01874 const GLint elemSizeVec = (elemSize + 3) / 4; /* number of vec4 */ 01875 struct prog_instruction *inst; 01876 01877 assert(n->Opcode == IR_ELEMENT); 01878 assert(elemSize > 0); 01879 01880 /* special case for built-in state variables, like light state */ 01881 { 01882 slang_ir_storage *root = n->Store; 01883 assert(!root->Parent); 01884 while (root->Parent) 01885 root = root->Parent; 01886 01887 if (root->File == PROGRAM_STATE_VAR) { 01888 GLboolean direct; 01889 GLint index = 01890 _slang_alloc_statevar(n, emitInfo->prog->Parameters, &direct); 01891 if (index < 0) { 01892 /* error */ 01893 return NULL; 01894 } 01895 if (direct) { 01896 n->Store->Index = index; 01897 return NULL; /* all done */ 01898 } 01899 } 01900 } 01901 01902 /* do codegen for array itself */ 01903 emit(emitInfo, n->Children[0]); 01904 arrayStore = n->Children[0]->Store; 01905 01906 /* The initial array element storage is the array's storage, 01907 * then modified below. 01908 */ 01909 _slang_copy_ir_storage(n->Store, arrayStore); 01910 01911 01912 if (n->Children[1]->Opcode == IR_FLOAT) { 01913 /* Constant array index */ 01914 const GLint element = (GLint) n->Children[1]->Value[0]; 01915 01916 /* this element's storage is the array's storage, plus constant offset */ 01917 n->Store->Index += elemSizeVec * element; 01918 } 01919 else { 01920 /* Variable array index */ 01921 01922 /* do codegen for array index expression */ 01923 emit(emitInfo, n->Children[1]); 01924 indexStore = n->Children[1]->Store; 01925 01926 if (indexStore->IsIndirect) { 01927 /* need to put the array index into a temporary since we can't 01928 * directly support a[b[i]] constructs. 01929 */ 01930 01931 01932 /*indexStore = tempstore();*/ 01933 } 01934 01935 01936 if (elemSize > 4) { 01937 /* need to multiply array index by array element size */ 01938 struct prog_instruction *inst; 01939 slang_ir_storage *indexTemp; 01940 slang_ir_storage elemSizeStore; 01941 01942 /* allocate 1 float indexTemp */ 01943 indexTemp = _slang_new_ir_storage(PROGRAM_TEMPORARY, -1, 1); 01944 _slang_alloc_temp(emitInfo->vt, indexTemp); 01945 01946 /* allocate a constant containing the element size */ 01947 constant_to_storage(emitInfo, (float) elemSizeVec, &elemSizeStore); 01948 01949 /* multiply array index by element size */ 01950 inst = emit_instruction(emitInfo, 01951 OPCODE_MUL, 01952 indexTemp, /* dest */ 01953 indexStore, /* the index */ 01954 &elemSizeStore, 01955 NULL); 01956 01957 indexStore = indexTemp; 01958 } 01959 01960 if (arrayStore->IsIndirect) { 01961 /* ex: in a[i][j], a[i] (the arrayStore) is indirect */ 01962 /* Need to add indexStore to arrayStore->Indirect store */ 01963 slang_ir_storage indirectArray; 01964 slang_ir_storage *indexTemp; 01965 01966 _slang_init_ir_storage(&indirectArray, 01967 arrayStore->IndirectFile, 01968 arrayStore->IndirectIndex, 01969 1, 01970 arrayStore->IndirectSwizzle); 01971 01972 /* allocate 1 float indexTemp */ 01973 indexTemp = _slang_new_ir_storage(PROGRAM_TEMPORARY, -1, 1); 01974 _slang_alloc_temp(emitInfo->vt, indexTemp); 01975 01976 inst = emit_instruction(emitInfo, 01977 OPCODE_ADD, 01978 indexTemp, /* dest */ 01979 indexStore, /* the index */ 01980 &indirectArray, /* indirect array base */ 01981 NULL); 01982 01983 indexStore = indexTemp; 01984 } 01985 01986 /* update the array element storage info */ 01987 n->Store->IsIndirect = GL_TRUE; 01988 n->Store->IndirectFile = indexStore->File; 01989 n->Store->IndirectIndex = indexStore->Index; 01990 n->Store->IndirectSwizzle = indexStore->Swizzle; 01991 } 01992 01993 n->Store->Size = elemSize; 01994 n->Store->Swizzle = _slang_var_swizzle(elemSize, 0); 01995 01996 return NULL; /* no instruction */ 01997 } 01998 01999 02003 static struct prog_instruction * 02004 emit_struct_field(slang_emit_info *emitInfo, slang_ir_node *n) 02005 { 02006 slang_ir_storage *root = n->Store; 02007 GLint fieldOffset, fieldSize; 02008 02009 assert(n->Opcode == IR_FIELD); 02010 02011 assert(!root->Parent); 02012 while (root->Parent) 02013 root = root->Parent; 02014 02015 /* If this is the field of a state var, allocate constant/uniform 02016 * storage for it now if we haven't already. 02017 * Note that we allocate storage (uniform/constant slots) for state 02018 * variables here rather than at declaration time so we only allocate 02019 * space for the ones that we actually use! 02020 */ 02021 if (root->File == PROGRAM_STATE_VAR) { 02022 GLboolean direct; 02023 GLint index = _slang_alloc_statevar(n, emitInfo->prog->Parameters, &direct); 02024 if (index < 0) { 02025 slang_info_log_error(emitInfo->log, "Error parsing state variable"); 02026 return NULL; 02027 } 02028 if (direct) { 02029 root->Index = index; 02030 return NULL; /* all done */ 02031 } 02032 } 02033 02034 /* do codegen for struct */ 02035 emit(emitInfo, n->Children[0]); 02036 assert(n->Children[0]->Store->Index >= 0); 02037 02038 02039 fieldOffset = n->Store->Index; 02040 fieldSize = n->Store->Size; 02041 02042 _slang_copy_ir_storage(n->Store, n->Children[0]->Store); 02043 02044 n->Store->Index = n->Children[0]->Store->Index + fieldOffset / 4; 02045 n->Store->Size = fieldSize; 02046 02047 switch (fieldSize) { 02048 case 1: 02049 { 02050 GLint swz = fieldOffset % 4; 02051 n->Store->Swizzle = MAKE_SWIZZLE4(swz, swz, swz, swz); 02052 } 02053 break; 02054 case 2: 02055 n->Store->Swizzle = MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, 02056 SWIZZLE_NIL, SWIZZLE_NIL); 02057 break; 02058 case 3: 02059 n->Store->Swizzle = MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, 02060 SWIZZLE_Z, SWIZZLE_NIL); 02061 break; 02062 default: 02063 n->Store->Swizzle = SWIZZLE_XYZW; 02064 } 02065 02066 assert(n->Store->Index >= 0); 02067 02068 return NULL; /* no instruction */ 02069 } 02070 02071 02077 static struct prog_instruction * 02078 emit_var_decl(slang_emit_info *emitInfo, slang_ir_node *n) 02079 { 02080 assert(n->Store); 02081 assert(n->Store->File != PROGRAM_UNDEFINED); 02082 assert(n->Store->Size > 0); 02083 /*assert(n->Store->Index < 0);*/ 02084 02085 if (!n->Var || n->Var->isTemp) { 02086 /* a nameless/temporary variable, will be freed after first use */ 02087 /*NEW*/ 02088 if (n->Store->Index < 0 && !_slang_alloc_temp(emitInfo->vt, n->Store)) { 02089 slang_info_log_error(emitInfo->log, 02090 "Ran out of registers, too many temporaries"); 02091 return NULL; 02092 } 02093 } 02094 else { 02095 /* a regular variable */ 02096 _slang_add_variable(emitInfo->vt, n->Var); 02097 if (!_slang_alloc_var(emitInfo->vt, n->Store)) { 02098 slang_info_log_error(emitInfo->log, 02099 "Ran out of registers, too many variables"); 02100 return NULL; 02101 } 02102 /* 02103 printf("IR_VAR_DECL %s %d store %p\n", 02104 (char*) n->Var->a_name, n->Store->Index, (void*) n->Store); 02105 */ 02106 assert(n->Var->store == n->Store); 02107 } 02108 if (emitInfo->EmitComments) { 02109 /* emit NOP with comment describing the variable's storage location */ 02110 char s[1000]; 02111 sprintf(s, "TEMP[%d]%s = variable %s (size %d)", 02112 n->Store->Index, 02113 _mesa_swizzle_string(n->Store->Swizzle, 0, GL_FALSE), 02114 (n->Var ? (char *) n->Var->a_name : "anonymous"), 02115 n->Store->Size); 02116 emit_comment(emitInfo, s); 02117 } 02118 return NULL; 02119 } 02120 02121 02127 static struct prog_instruction * 02128 emit_var_ref(slang_emit_info *emitInfo, slang_ir_node *n) 02129 { 02130 assert(n->Store); 02131 assert(n->Store->File != PROGRAM_UNDEFINED); 02132 02133 if (n->Store->File == PROGRAM_STATE_VAR && n->Store->Index < 0) { 02134 GLboolean direct; 02135 GLint index = _slang_alloc_statevar(n, emitInfo->prog->Parameters, &direct); 02136 if (index < 0) { 02137 /* error */ 02138 char s[100]; 02139 _mesa_snprintf(s, sizeof(s), "Undefined variable '%s'", 02140 (char *) n->Var->a_name); 02141 slang_info_log_error(emitInfo->log, s); 02142 return NULL; 02143 } 02144 02145 n->Store->Index = index; 02146 } 02147 else if (n->Store->File == PROGRAM_UNIFORM || 02148 n->Store->File == PROGRAM_SAMPLER) { 02149 /* mark var as used */ 02150 _mesa_use_uniform(emitInfo->prog->Parameters, (char *) n->Var->a_name); 02151 } 02152 else if (n->Store->File == PROGRAM_INPUT) { 02153 assert(n->Store->Index >= 0); 02154 emitInfo->prog->InputsRead |= (1 << n->Store->Index); 02155 } 02156 02157 if (n->Store->Index < 0) { 02158 /* probably ran out of registers */ 02159 return NULL; 02160 } 02161 assert(n->Store->Size > 0); 02162 02163 return NULL; 02164 } 02165 02166 02167 static struct prog_instruction * 02168 emit(slang_emit_info *emitInfo, slang_ir_node *n) 02169 { 02170 struct prog_instruction *inst; 02171 if (!n) 02172 return NULL; 02173 02174 if (emitInfo->log->error_flag) { 02175 return NULL; 02176 } 02177 02178 switch (n->Opcode) { 02179 case IR_SEQ: 02180 /* sequence of two sub-trees */ 02181 assert(n->Children[0]); 02182 assert(n->Children[1]); 02183 emit(emitInfo, n->Children[0]); 02184 if (emitInfo->log->error_flag) 02185 return NULL; 02186 inst = emit(emitInfo, n->Children[1]); 02187 #if 0 02188 assert(!n->Store); 02189 #endif 02190 n->Store = n->Children[1]->Store; 02191 return inst; 02192 02193 case IR_SCOPE: 02194 /* new variable scope */ 02195 _slang_push_var_table(emitInfo->vt); 02196 inst = emit(emitInfo, n->Children[0]); 02197 _slang_pop_var_table(emitInfo->vt); 02198 return inst; 02199 02200 case IR_VAR_DECL: 02201 /* Variable declaration - allocate a register for it */ 02202 inst = emit_var_decl(emitInfo, n); 02203 return inst; 02204 02205 case IR_VAR: 02206 /* Reference to a variable 02207 * Storage should have already been resolved/allocated. 02208 */ 02209 return emit_var_ref(emitInfo, n); 02210 02211 case IR_ELEMENT: 02212 return emit_array_element(emitInfo, n); 02213 case IR_FIELD: 02214 return emit_struct_field(emitInfo, n); 02215 case IR_SWIZZLE: 02216 return emit_swizzle(emitInfo, n); 02217 02218 /* Simple arithmetic */ 02219 /* unary */ 02220 case IR_MOVE: 02221 case IR_RSQ: 02222 case IR_RCP: 02223 case IR_FLOOR: 02224 case IR_FRAC: 02225 case IR_F_TO_I: 02226 case IR_I_TO_F: 02227 case IR_ABS: 02228 case IR_SIN: 02229 case IR_COS: 02230 case IR_DDX: 02231 case IR_DDY: 02232 case IR_EXP: 02233 case IR_EXP2: 02234 case IR_LOG2: 02235 case IR_NOISE1: 02236 case IR_NOISE2: 02237 case IR_NOISE3: 02238 case IR_NOISE4: 02239 case IR_NRM4: 02240 case IR_NRM3: 02241 /* binary */ 02242 case IR_ADD: 02243 case IR_SUB: 02244 case IR_MUL: 02245 case IR_DOT4: 02246 case IR_DOT3: 02247 case IR_DOT2: 02248 case IR_CROSS: 02249 case IR_MIN: 02250 case IR_MAX: 02251 case IR_SEQUAL: 02252 case IR_SNEQUAL: 02253 case IR_SGE: 02254 case IR_SGT: 02255 case IR_SLE: 02256 case IR_SLT: 02257 case IR_POW: 02258 /* trinary operators */ 02259 case IR_LRP: 02260 return emit_arith(emitInfo, n); 02261 02262 case IR_EQUAL: 02263 case IR_NOTEQUAL: 02264 return emit_compare(emitInfo, n); 02265 02266 case IR_CLAMP: 02267 return emit_clamp(emitInfo, n); 02268 case IR_TEX: 02269 case IR_TEXB: 02270 case IR_TEXP: 02271 return emit_tex(emitInfo, n); 02272 case IR_NEG: 02273 return emit_negation(emitInfo, n); 02274 case IR_FLOAT: 02275 /* find storage location for this float constant */ 02276 n->Store->Index = _mesa_add_unnamed_constant(emitInfo->prog->Parameters, 02277 n->Value, 02278 n->Store->Size, 02279 &n->Store->Swizzle); 02280 if (n->Store->Index < 0) { 02281 slang_info_log_error(emitInfo->log, "Ran out of space for constants"); 02282 return NULL; 02283 } 02284 return NULL; 02285 02286 case IR_COPY: 02287 return emit_copy(emitInfo, n); 02288 02289 case IR_COND: 02290 return emit_cond(emitInfo, n); 02291 02292 case IR_NOT: 02293 return emit_not(emitInfo, n); 02294 02295 case IR_LABEL: 02296 return emit_label(emitInfo, n); 02297 02298 case IR_KILL: 02299 return emit_kill(emitInfo); 02300 02301 case IR_CALL: 02302 /* new variable scope for subroutines/function calls */ 02303 _slang_push_var_table(emitInfo->vt); 02304 inst = emit_fcall(emitInfo, n); 02305 _slang_pop_var_table(emitInfo->vt); 02306 return inst; 02307 02308 case IR_IF: 02309 return emit_if(emitInfo, n); 02310 02311 case IR_LOOP: 02312 return emit_loop(emitInfo, n); 02313 case IR_BREAK_IF_TRUE: 02314 case IR_CONT_IF_TRUE: 02315 return emit_cont_break_if_true(emitInfo, n); 02316 case IR_BREAK: 02317 /* fall-through */ 02318 case IR_CONT: 02319 return emit_cont_break(emitInfo, n); 02320 02321 case IR_BEGIN_SUB: 02322 return new_instruction(emitInfo, OPCODE_BGNSUB); 02323 case IR_END_SUB: 02324 return new_instruction(emitInfo, OPCODE_ENDSUB); 02325 case IR_RETURN: 02326 return emit_return(emitInfo, n); 02327 02328 case IR_NOP: 02329 return NULL; 02330 02331 default: 02332 _mesa_problem(NULL, "Unexpected IR opcode in emit()\n"); 02333 } 02334 return NULL; 02335 } 02336 02337 02344 static void 02345 _slang_resolve_subroutines(slang_emit_info *emitInfo) 02346 { 02347 GET_CURRENT_CONTEXT(ctx); 02348 struct gl_program *mainP = emitInfo->prog; 02349 GLuint *subroutineLoc, i, total; 02350 02351 subroutineLoc 02352 = (GLuint *) _mesa_malloc(emitInfo->NumSubroutines * sizeof(GLuint)); 02353 02354 /* total number of instructions */ 02355 total = mainP->NumInstructions; 02356 for (i = 0; i < emitInfo->NumSubroutines; i++) { 02357 subroutineLoc[i] = total; 02358 total += emitInfo->Subroutines[i]->NumInstructions; 02359 } 02360 02361 /* adjust BranchTargets within the functions */ 02362 for (i = 0; i < emitInfo->NumSubroutines; i++) { 02363 struct gl_program *sub = emitInfo->Subroutines[i]; 02364 GLuint j; 02365 for (j = 0; j < sub->NumInstructions; j++) { 02366 struct prog_instruction *inst = sub->Instructions + j; 02367 if (inst->Opcode != OPCODE_CAL && inst->BranchTarget >= 0) { 02368 inst->BranchTarget += subroutineLoc[i]; 02369 } 02370 } 02371 } 02372 02373 /* append subroutines' instructions after main's instructions */ 02374 mainP->Instructions = _mesa_realloc_instructions(mainP->Instructions, 02375 mainP->NumInstructions, 02376 total); 02377 mainP->NumInstructions = total; 02378 for (i = 0; i < emitInfo->NumSubroutines; i++) { 02379 struct gl_program *sub = emitInfo->Subroutines[i]; 02380 _mesa_copy_instructions(mainP->Instructions + subroutineLoc[i], 02381 sub->Instructions, 02382 sub->NumInstructions); 02383 /* delete subroutine code */ 02384 sub->Parameters = NULL; /* prevent double-free */ 02385 _mesa_reference_program(ctx, &emitInfo->Subroutines[i], NULL); 02386 } 02387 02388 /* free subroutine list */ 02389 if (emitInfo->Subroutines) { 02390 _mesa_free(emitInfo->Subroutines); 02391 emitInfo->Subroutines = NULL; 02392 } 02393 emitInfo->NumSubroutines = 0; 02394 02395 /* Examine CAL instructions. 02396 * At this point, the BranchTarget field of the CAL instruction is 02397 * the number/id of the subroutine to call (an index into the 02398 * emitInfo->Subroutines list). 02399 * Translate that into an actual instruction location now. 02400 */ 02401 for (i = 0; i < mainP->NumInstructions; i++) { 02402 struct prog_instruction *inst = mainP->Instructions + i; 02403 if (inst->Opcode == OPCODE_CAL) { 02404 const GLuint f = inst->BranchTarget; 02405 inst->BranchTarget = subroutineLoc[f]; 02406 } 02407 } 02408 02409 _mesa_free(subroutineLoc); 02410 } 02411 02412 02413 02423 GLboolean 02424 _slang_emit_code(slang_ir_node *n, slang_var_table *vt, 02425 struct gl_program *prog, 02426 const struct gl_sl_pragmas *pragmas, 02427 GLboolean withEnd, 02428 slang_info_log *log) 02429 { 02430 GET_CURRENT_CONTEXT(ctx); 02431 GLboolean success; 02432 slang_emit_info emitInfo; 02433 GLuint maxUniforms; 02434 02435 emitInfo.log = log; 02436 emitInfo.vt = vt; 02437 emitInfo.prog = prog; 02438 emitInfo.Subroutines = NULL; 02439 emitInfo.NumSubroutines = 0; 02440 emitInfo.MaxInstructions = prog->NumInstructions; 02441 02442 emitInfo.EmitHighLevelInstructions = ctx->Shader.EmitHighLevelInstructions; 02443 emitInfo.EmitCondCodes = ctx->Shader.EmitCondCodes; 02444 emitInfo.EmitComments = ctx->Shader.EmitComments || pragmas->Debug; 02445 emitInfo.EmitBeginEndSub = GL_TRUE; 02446 02447 if (!emitInfo.EmitCondCodes) { 02448 emitInfo.EmitHighLevelInstructions = GL_TRUE; 02449 } 02450 02451 /* Check uniform/constant limits */ 02452 if (prog->Target == GL_FRAGMENT_PROGRAM_ARB) { 02453 maxUniforms = ctx->Const.FragmentProgram.MaxUniformComponents / 4; 02454 } 02455 else { 02456 assert(prog->Target == GL_VERTEX_PROGRAM_ARB); 02457 maxUniforms = ctx->Const.VertexProgram.MaxUniformComponents / 4; 02458 } 02459 if (prog->Parameters->NumParameters > maxUniforms) { 02460 slang_info_log_error(log, "Constant/uniform register limit exceeded " 02461 "(max=%u vec4)", maxUniforms); 02462 02463 return GL_FALSE; 02464 } 02465 02466 (void) emit(&emitInfo, n); 02467 02468 /* finish up by adding the END opcode to program */ 02469 if (withEnd) { 02470 struct prog_instruction *inst; 02471 inst = new_instruction(&emitInfo, OPCODE_END); 02472 } 02473 02474 _slang_resolve_subroutines(&emitInfo); 02475 02476 success = GL_TRUE; 02477 02478 #if 0 02479 printf("*********** End emit code (%u inst):\n", prog->NumInstructions); 02480 _mesa_print_program(prog); 02481 _mesa_print_program_parameters(ctx,prog); 02482 #endif 02483 02484 return success; 02485 } Generated on Sun May 27 2012 04:20:40 for ReactOS by
1.7.6.1
|