ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

slang_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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.