Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * Mesa 3-D graphics library
  3.  *
  4.  * Copyright (C) 2012-2013 LunarG, Inc.
  5.  *
  6.  * Permission is hereby granted, free of charge, to any person obtaining a
  7.  * copy of this software and associated documentation files (the "Software"),
  8.  * to deal in the Software without restriction, including without limitation
  9.  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  10.  * and/or sell copies of the Software, and to permit persons to whom the
  11.  * Software is furnished to do so, subject to the following conditions:
  12.  *
  13.  * The above copyright notice and this permission notice shall be included
  14.  * in all copies or substantial portions of the Software.
  15.  *
  16.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17.  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18.  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  19.  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20.  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  21.  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  22.  * DEALINGS IN THE SOFTWARE.
  23.  *
  24.  * Authors:
  25.  *    Chia-I Wu <olv@lunarg.com>
  26.  */
  27.  
  28. #include "pipe/p_shader_tokens.h"
  29. #include "toy_compiler.h"
  30. #include "toy_tgsi.h"
  31. #include "toy_helpers.h"
  32. #include "toy_legalize.h"
  33.  
  34. /**
  35.  * Lower an instruction to BRW_OPCODE_SEND(C).
  36.  */
  37. void
  38. toy_compiler_lower_to_send(struct toy_compiler *tc, struct toy_inst *inst,
  39.                            bool sendc, unsigned sfid)
  40. {
  41.    assert(inst->opcode >= 128);
  42.  
  43.    inst->opcode = (sendc) ? BRW_OPCODE_SENDC : BRW_OPCODE_SEND;
  44.  
  45.    /* thread control is reserved */
  46.    assert(inst->thread_ctrl == 0);
  47.  
  48.    assert(inst->cond_modifier == BRW_CONDITIONAL_NONE);
  49.    inst->cond_modifier = sfid;
  50. }
  51.  
  52. static int
  53. math_op_to_func(unsigned opcode)
  54. {
  55.    switch (opcode) {
  56.    case TOY_OPCODE_INV:    return BRW_MATH_FUNCTION_INV;
  57.    case TOY_OPCODE_LOG:    return BRW_MATH_FUNCTION_LOG;
  58.    case TOY_OPCODE_EXP:    return BRW_MATH_FUNCTION_EXP;
  59.    case TOY_OPCODE_SQRT:   return BRW_MATH_FUNCTION_SQRT;
  60.    case TOY_OPCODE_RSQ:    return BRW_MATH_FUNCTION_RSQ;
  61.    case TOY_OPCODE_SIN:    return BRW_MATH_FUNCTION_SIN;
  62.    case TOY_OPCODE_COS:    return BRW_MATH_FUNCTION_COS;
  63.    case TOY_OPCODE_FDIV:   return BRW_MATH_FUNCTION_FDIV;
  64.    case TOY_OPCODE_POW:    return BRW_MATH_FUNCTION_POW;
  65.    case TOY_OPCODE_INT_DIV_QUOTIENT:   return BRW_MATH_FUNCTION_INT_DIV_QUOTIENT;
  66.    case TOY_OPCODE_INT_DIV_REMAINDER:  return BRW_MATH_FUNCTION_INT_DIV_REMAINDER;
  67.    default:
  68.        assert(!"unknown math opcode");
  69.        return -1;
  70.    }
  71. }
  72.  
  73. /**
  74.  * Lower virtual math opcodes to BRW_OPCODE_MATH.
  75.  */
  76. void
  77. toy_compiler_lower_math(struct toy_compiler *tc, struct toy_inst *inst)
  78. {
  79.    struct toy_dst tmp;
  80.    int i;
  81.  
  82.    /* see commit 250770b74d33bb8625c780a74a89477af033d13a */
  83.    for (i = 0; i < Elements(inst->src); i++) {
  84.       if (tsrc_is_null(inst->src[i]))
  85.          break;
  86.  
  87.       /* no swizzling in align1 */
  88.       /* XXX how about source modifiers? */
  89.       if (toy_file_is_virtual(inst->src[i].file) &&
  90.           !tsrc_is_swizzled(inst->src[i]) &&
  91.           !inst->src[i].absolute &&
  92.           !inst->src[i].negate)
  93.          continue;
  94.  
  95.       tmp = tdst_type(tc_alloc_tmp(tc), inst->src[i].type);
  96.       tc_MOV(tc, tmp, inst->src[i]);
  97.       inst->src[i] = tsrc_from(tmp);
  98.    }
  99.  
  100.    /* FC[0:3] */
  101.    assert(inst->cond_modifier == BRW_CONDITIONAL_NONE);
  102.    inst->cond_modifier = math_op_to_func(inst->opcode);
  103.    /* FC[4:5] */
  104.    assert(inst->thread_ctrl == 0);
  105.    inst->thread_ctrl = 0;
  106.  
  107.    inst->opcode = BRW_OPCODE_MATH;
  108.    tc_move_inst(tc, inst);
  109.  
  110.    /* no writemask in align1 */
  111.    if (inst->dst.writemask != TOY_WRITEMASK_XYZW) {
  112.       struct toy_dst dst = inst->dst;
  113.       struct toy_inst *inst2;
  114.  
  115.       tmp = tc_alloc_tmp(tc);
  116.       tmp.type = inst->dst.type;
  117.       inst->dst = tmp;
  118.  
  119.       inst2 = tc_MOV(tc, dst, tsrc_from(tmp));
  120.       inst2->pred_ctrl = inst->pred_ctrl;
  121.    }
  122. }
  123.  
  124. static uint32_t
  125. absolute_imm(uint32_t imm32, enum toy_type type)
  126. {
  127.    union fi val = { .ui = imm32 };
  128.  
  129.    switch (type) {
  130.    case TOY_TYPE_F:
  131.       val.f = fabs(val.f);
  132.       break;
  133.    case TOY_TYPE_D:
  134.       if (val.i < 0)
  135.          val.i = -val.i;
  136.       break;
  137.    case TOY_TYPE_W:
  138.       if ((int16_t) (val.ui & 0xffff) < 0)
  139.          val.i = -((int16_t) (val.ui & 0xffff));
  140.       break;
  141.    case TOY_TYPE_V:
  142.       assert(!"cannot take absoulte of immediates of type V");
  143.       break;
  144.    default:
  145.       break;
  146.    }
  147.  
  148.    return val.ui;
  149. }
  150.  
  151. static uint32_t
  152. negate_imm(uint32_t imm32, enum toy_type type)
  153. {
  154.    union fi val = { .ui = imm32 };
  155.  
  156.    switch (type) {
  157.    case TOY_TYPE_F:
  158.       val.f = -val.f;
  159.       break;
  160.    case TOY_TYPE_D:
  161.    case TOY_TYPE_UD:
  162.       val.i = -val.i;
  163.       break;
  164.    case TOY_TYPE_W:
  165.    case TOY_TYPE_UW:
  166.       val.i = -((int16_t) (val.ui & 0xffff));
  167.       break;
  168.    default:
  169.       assert(!"negate immediate of unknown type");
  170.       break;
  171.    }
  172.  
  173.    return val.ui;
  174. }
  175.  
  176. static void
  177. validate_imm(struct toy_compiler *tc, struct toy_inst *inst)
  178. {
  179.    bool move_inst = false;
  180.    int i;
  181.  
  182.    for (i = 0; i < Elements(inst->src); i++) {
  183.       struct toy_dst tmp;
  184.  
  185.       if (tsrc_is_null(inst->src[i]))
  186.          break;
  187.  
  188.       if (inst->src[i].file != TOY_FILE_IMM)
  189.          continue;
  190.  
  191.       if (inst->src[i].absolute) {
  192.          inst->src[i].val32 =
  193.             absolute_imm(inst->src[i].val32, inst->src[i].type);
  194.          inst->src[i].absolute = false;
  195.       }
  196.  
  197.       if (inst->src[i].negate) {
  198.          inst->src[i].val32 =
  199.             negate_imm(inst->src[i].val32, inst->src[i].type);
  200.          inst->src[i].negate = false;
  201.       }
  202.  
  203.       /* this is the last operand */
  204.       if (i + 1 == Elements(inst->src) || tsrc_is_null(inst->src[i + 1]))
  205.          break;
  206.  
  207.       /* need to use a temp if this imm is not the last operand */
  208.       /* TODO we should simply swap the operands if the op is commutative */
  209.       tmp = tc_alloc_tmp(tc);
  210.       tmp = tdst_type(tmp, inst->src[i].type);
  211.       tc_MOV(tc, tmp, inst->src[i]);
  212.       inst->src[i] = tsrc_from(tmp);
  213.  
  214.       move_inst = true;
  215.    }
  216.  
  217.    if (move_inst)
  218.       tc_move_inst(tc, inst);
  219. }
  220.  
  221. static void
  222. lower_opcode_mul(struct toy_compiler *tc, struct toy_inst *inst)
  223. {
  224.    const enum toy_type inst_type = inst->dst.type;
  225.    const struct toy_dst acc0 =
  226.       tdst_type(tdst(TOY_FILE_ARF, BRW_ARF_ACCUMULATOR, 0), inst_type);
  227.    struct toy_inst *inst2;
  228.  
  229.    /* only need to take care of integer multiplications */
  230.    if (inst_type != TOY_TYPE_UD && inst_type != TOY_TYPE_D)
  231.       return;
  232.  
  233.    /* acc0 = (src0 & 0x0000ffff) * src1 */
  234.    tc_MUL(tc, acc0, inst->src[0], inst->src[1]);
  235.  
  236.    /* acc0 = (src0 & 0xffff0000) * src1 + acc0 */
  237.    inst2 = tc_add2(tc, BRW_OPCODE_MACH, tdst_type(tdst_null(), inst_type),
  238.          inst->src[0], inst->src[1]);
  239.    inst2->acc_wr_ctrl = true;
  240.  
  241.    /* dst = acc0 & 0xffffffff */
  242.    tc_MOV(tc, inst->dst, tsrc_from(acc0));
  243.  
  244.    tc_discard_inst(tc, inst);
  245. }
  246.  
  247. static void
  248. lower_opcode_mac(struct toy_compiler *tc, struct toy_inst *inst)
  249. {
  250.    const enum toy_type inst_type = inst->dst.type;
  251.  
  252.    if (inst_type != TOY_TYPE_UD && inst_type != TOY_TYPE_D) {
  253.       const struct toy_dst acc0 = tdst(TOY_FILE_ARF, BRW_ARF_ACCUMULATOR, 0);
  254.  
  255.       tc_MOV(tc, acc0, inst->src[2]);
  256.       inst->src[2] = tsrc_null();
  257.       tc_move_inst(tc, inst);
  258.    }
  259.    else {
  260.       struct toy_dst tmp = tdst_type(tc_alloc_tmp(tc), inst_type);
  261.       struct toy_inst *inst2;
  262.  
  263.       inst2 = tc_MUL(tc, tmp, inst->src[0], inst->src[1]);
  264.       lower_opcode_mul(tc, inst2);
  265.  
  266.       tc_ADD(tc, inst->dst, tsrc_from(tmp), inst->src[2]);
  267.  
  268.       tc_discard_inst(tc, inst);
  269.    }
  270. }
  271.  
  272. /**
  273.  * Legalize the instructions for register allocation.
  274.  */
  275. void
  276. toy_compiler_legalize_for_ra(struct toy_compiler *tc)
  277. {
  278.    struct toy_inst *inst;
  279.  
  280.    tc_head(tc);
  281.    while ((inst = tc_next(tc)) != NULL) {
  282.       switch (inst->opcode) {
  283.       case BRW_OPCODE_MAC:
  284.          lower_opcode_mac(tc, inst);
  285.          break;
  286.       case BRW_OPCODE_MAD:
  287.          /* TODO operands must be floats */
  288.          break;
  289.       case BRW_OPCODE_MUL:
  290.          lower_opcode_mul(tc, inst);
  291.          break;
  292.       default:
  293.          if (inst->opcode > TOY_OPCODE_LAST_HW)
  294.             tc_fail(tc, "internal opcodes not lowered");
  295.       }
  296.    }
  297.  
  298.    /* loop again as the previous pass may add new instructions */
  299.    tc_head(tc);
  300.    while ((inst = tc_next(tc)) != NULL) {
  301.       validate_imm(tc, inst);
  302.    }
  303. }
  304.  
  305. static void
  306. patch_while_jip(struct toy_compiler *tc, struct toy_inst *inst)
  307. {
  308.    struct toy_inst *inst2;
  309.    int nest_level, dist;
  310.  
  311.    nest_level = 0;
  312.    dist = -1;
  313.  
  314.    /* search backward */
  315.    LIST_FOR_EACH_ENTRY_FROM_REV(inst2, inst->list.prev,
  316.          &tc->instructions, list) {
  317.       if (inst2->marker) {
  318.          if (inst2->opcode == BRW_OPCODE_DO) {
  319.             if (nest_level) {
  320.                nest_level--;
  321.             }
  322.             else {
  323.                /* the following instruction */
  324.                dist++;
  325.                break;
  326.             }
  327.          }
  328.  
  329.          continue;
  330.       }
  331.  
  332.       if (inst2->opcode == BRW_OPCODE_WHILE)
  333.          nest_level++;
  334.  
  335.       dist--;
  336.    }
  337.  
  338.    if (tc->dev->gen >= ILO_GEN(7))
  339.       inst->src[1] = tsrc_imm_w(dist * 2);
  340.    else
  341.       inst->dst = tdst_imm_w(dist * 2);
  342. }
  343.  
  344. static void
  345. patch_if_else_jip(struct toy_compiler *tc, struct toy_inst *inst)
  346. {
  347.    struct toy_inst *inst2;
  348.    int nest_level, dist;
  349.    int jip, uip;
  350.  
  351.    nest_level = 0;
  352.    dist = 1;
  353.    jip = 0;
  354.    uip = 0;
  355.  
  356.    /* search forward */
  357.    LIST_FOR_EACH_ENTRY_FROM(inst2, inst->list.next, &tc->instructions, list) {
  358.       if (inst2->marker)
  359.          continue;
  360.  
  361.       if (inst2->opcode == BRW_OPCODE_ENDIF) {
  362.          if (nest_level) {
  363.             nest_level--;
  364.          }
  365.          else {
  366.             uip = dist * 2;
  367.             if (!jip)
  368.                jip = uip;
  369.             break;
  370.          }
  371.       }
  372.       else if (inst2->opcode == BRW_OPCODE_ELSE &&
  373.                inst->opcode == BRW_OPCODE_IF) {
  374.          if (!nest_level) {
  375.             /* the following instruction */
  376.             jip = (dist + 1) * 2;
  377.  
  378.             if (tc->dev->gen == ILO_GEN(6)) {
  379.                uip = jip;
  380.                break;
  381.             }
  382.          }
  383.       }
  384.       else if (inst2->opcode == BRW_OPCODE_IF) {
  385.          nest_level++;
  386.       }
  387.  
  388.       dist++;
  389.    }
  390.  
  391.    if (tc->dev->gen >= ILO_GEN(7)) {
  392.       /* what should the type be? */
  393.       inst->dst.type = TOY_TYPE_D;
  394.       inst->src[0].type = TOY_TYPE_D;
  395.       inst->src[1] = tsrc_imm_d(uip << 16 | jip);
  396.    }
  397.    else {
  398.       inst->dst = tdst_imm_w(jip);
  399.    }
  400.  
  401.    inst->thread_ctrl = BRW_THREAD_SWITCH;
  402. }
  403.  
  404. static void
  405. patch_endif_jip(struct toy_compiler *tc, struct toy_inst *inst)
  406. {
  407.    struct toy_inst *inst2;
  408.    bool found = false;
  409.    int dist = 1;
  410.  
  411.    /* search forward for instructions that may enable channels */
  412.    LIST_FOR_EACH_ENTRY_FROM(inst2, inst->list.next, &tc->instructions, list) {
  413.       if (inst2->marker)
  414.          continue;
  415.  
  416.       switch (inst2->opcode) {
  417.       case BRW_OPCODE_ENDIF:
  418.       case BRW_OPCODE_ELSE:
  419.       case BRW_OPCODE_WHILE:
  420.          found = true;
  421.          break;
  422.       default:
  423.          break;
  424.       }
  425.  
  426.       if (found)
  427.          break;
  428.  
  429.       dist++;
  430.    }
  431.  
  432.    /* should we set dist to (dist - 1) or 1? */
  433.    if (!found)
  434.       dist = 1;
  435.  
  436.    if (tc->dev->gen >= ILO_GEN(7))
  437.       inst->src[1] = tsrc_imm_w(dist * 2);
  438.    else
  439.       inst->dst = tdst_imm_w(dist * 2);
  440.  
  441.    inst->thread_ctrl = BRW_THREAD_SWITCH;
  442. }
  443.  
  444. static void
  445. patch_break_continue_jip(struct toy_compiler *tc, struct toy_inst *inst)
  446. {
  447.    struct toy_inst *inst2, *inst3;
  448.    int nest_level, dist, jip, uip;
  449.  
  450.    nest_level = 0;
  451.    dist = 1;
  452.    jip = 1 * 2;
  453.    uip = 1 * 2;
  454.  
  455.    /* search forward */
  456.    LIST_FOR_EACH_ENTRY_FROM(inst2, inst->list.next, &tc->instructions, list) {
  457.       if (inst2->marker) {
  458.          if (inst2->opcode == BRW_OPCODE_DO)
  459.             nest_level++;
  460.          continue;
  461.       }
  462.  
  463.       if (inst2->opcode == BRW_OPCODE_ELSE ||
  464.           inst2->opcode == BRW_OPCODE_ENDIF ||
  465.           inst2->opcode == BRW_OPCODE_WHILE) {
  466.          jip = dist * 2;
  467.          break;
  468.       }
  469.  
  470.       dist++;
  471.    }
  472.  
  473.    /* go on to determine uip */
  474.    inst3 = inst2;
  475.    LIST_FOR_EACH_ENTRY_FROM(inst2, &inst3->list, &tc->instructions, list) {
  476.       if (inst2->marker) {
  477.          if (inst2->opcode == BRW_OPCODE_DO)
  478.             nest_level++;
  479.          continue;
  480.       }
  481.  
  482.       if (inst2->opcode == BRW_OPCODE_WHILE) {
  483.          if (nest_level) {
  484.             nest_level--;
  485.          }
  486.          else {
  487.             /* the following instruction */
  488.             if (tc->dev->gen == ILO_GEN(6) && inst->opcode == BRW_OPCODE_BREAK)
  489.                dist++;
  490.  
  491.             uip = dist * 2;
  492.             break;
  493.          }
  494.       }
  495.  
  496.       dist++;
  497.    }
  498.  
  499.    /* should the type be D or W? */
  500.    inst->dst.type = TOY_TYPE_D;
  501.    inst->src[0].type = TOY_TYPE_D;
  502.    inst->src[1] = tsrc_imm_d(uip << 16 | jip);
  503. }
  504.  
  505. /**
  506.  * Legalize the instructions for assembling.
  507.  */
  508. void
  509. toy_compiler_legalize_for_asm(struct toy_compiler *tc)
  510. {
  511.    struct toy_inst *inst;
  512.    int pc = 0;
  513.  
  514.    tc_head(tc);
  515.    while ((inst = tc_next(tc)) != NULL) {
  516.       int i;
  517.  
  518.       pc++;
  519.  
  520.       /*
  521.        * From the Sandy Bridge PRM, volume 4 part 2, page 112:
  522.        *
  523.        *     "Specifically, for instructions with a single source, it only
  524.        *      uses the first source operand <src0>. In this case, the second
  525.        *      source operand <src1> must be set to null and also with the same
  526.        *      type as the first source operand <src0>.  It is a special case
  527.        *      when <src0> is an immediate, as an immediate <src0> uses DW3 of
  528.        *      the instruction word, which is normally used by <src1>.  In this
  529.        *      case, <src1> must be programmed with register file ARF and the
  530.        *      same data type as <src0>."
  531.        *
  532.        * Since we already fill unused operands with null, we only need to take
  533.        * care of the type.
  534.        */
  535.       if (tsrc_is_null(inst->src[1]))
  536.          inst->src[1].type = inst->src[0].type;
  537.  
  538.       switch (inst->opcode) {
  539.       case BRW_OPCODE_MATH:
  540.          /* math does not support align16 nor exec_size > 8 */
  541.          inst->access_mode = BRW_ALIGN_1;
  542.  
  543.          if (inst->exec_size == BRW_EXECUTE_16) {
  544.             /*
  545.              * From the Ivy Bridge PRM, volume 4 part 3, page 192:
  546.              *
  547.              *     "INT DIV function does not support SIMD16."
  548.              */
  549.             if (tc->dev->gen < ILO_GEN(7) ||
  550.                 inst->cond_modifier == BRW_MATH_FUNCTION_INT_DIV_QUOTIENT ||
  551.                 inst->cond_modifier == BRW_MATH_FUNCTION_INT_DIV_REMAINDER) {
  552.                struct toy_inst *inst2;
  553.  
  554.                inst->exec_size = BRW_EXECUTE_8;
  555.                inst->qtr_ctrl = GEN6_COMPRESSION_1Q;
  556.  
  557.                inst2 = tc_duplicate_inst(tc, inst);
  558.                inst2->qtr_ctrl = GEN6_COMPRESSION_2Q;
  559.                inst2->dst = tdst_offset(inst2->dst, 1, 0);
  560.                inst2->src[0] = tsrc_offset(inst2->src[0], 1, 0);
  561.                if (!tsrc_is_null(inst2->src[1]))
  562.                   inst2->src[1] = tsrc_offset(inst2->src[1], 1, 0);
  563.  
  564.                pc++;
  565.             }
  566.          }
  567.          break;
  568.       case BRW_OPCODE_IF:
  569.          if (tc->dev->gen >= ILO_GEN(7) &&
  570.              inst->cond_modifier != BRW_CONDITIONAL_NONE) {
  571.             struct toy_inst *inst2;
  572.  
  573.             inst2 = tc_duplicate_inst(tc, inst);
  574.  
  575.             /* replace the original IF by CMP */
  576.             inst->opcode = BRW_OPCODE_CMP;
  577.  
  578.             /* predicate control instead of condition modifier */
  579.             inst2->dst = tdst_null();
  580.             inst2->src[0] = tsrc_null();
  581.             inst2->src[1] = tsrc_null();
  582.             inst2->cond_modifier = BRW_CONDITIONAL_NONE;
  583.             inst2->pred_ctrl = BRW_PREDICATE_NORMAL;
  584.  
  585.             pc++;
  586.          }
  587.          break;
  588.       default:
  589.          break;
  590.       }
  591.  
  592.       /* MRF to GRF */
  593.       if (tc->dev->gen >= ILO_GEN(7)) {
  594.          for (i = 0; i < Elements(inst->src); i++) {
  595.             if (inst->src[i].file != TOY_FILE_MRF)
  596.                continue;
  597.             else if (tsrc_is_null(inst->src[i]))
  598.                break;
  599.  
  600.             inst->src[i].file = TOY_FILE_GRF;
  601.          }
  602.  
  603.          if (inst->dst.file == TOY_FILE_MRF)
  604.             inst->dst.file = TOY_FILE_GRF;
  605.       }
  606.    }
  607.  
  608.    tc->num_instructions = pc;
  609.  
  610.    /* set JIP/UIP */
  611.    tc_head(tc);
  612.    while ((inst = tc_next(tc)) != NULL) {
  613.       switch (inst->opcode) {
  614.       case BRW_OPCODE_IF:
  615.       case BRW_OPCODE_ELSE:
  616.          patch_if_else_jip(tc, inst);
  617.          break;
  618.       case BRW_OPCODE_ENDIF:
  619.          patch_endif_jip(tc, inst);
  620.          break;
  621.       case BRW_OPCODE_WHILE:
  622.          patch_while_jip(tc, inst);
  623.          break;
  624.       case BRW_OPCODE_BREAK:
  625.       case BRW_OPCODE_CONTINUE:
  626.          patch_break_continue_jip(tc, inst);
  627.          break;
  628.       default:
  629.          break;
  630.       }
  631.    }
  632. }
  633.