Home | History | Annotate | Line # | Download | only in disassembler
dmcstyle.c revision 1.2.2.6
      1 /*******************************************************************************
      2  *
      3  * Module Name: dmcstyle - Support for C-style operator disassembly
      4  *
      5  ******************************************************************************/
      6 
      7 /*
      8  * Copyright (C) 2000 - 2016, Intel Corp.
      9  * All rights reserved.
     10  *
     11  * Redistribution and use in source and binary forms, with or without
     12  * modification, are permitted provided that the following conditions
     13  * are met:
     14  * 1. Redistributions of source code must retain the above copyright
     15  *    notice, this list of conditions, and the following disclaimer,
     16  *    without modification.
     17  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
     18  *    substantially similar to the "NO WARRANTY" disclaimer below
     19  *    ("Disclaimer") and any redistribution must be conditioned upon
     20  *    including a substantially similar Disclaimer requirement for further
     21  *    binary redistribution.
     22  * 3. Neither the names of the above-listed copyright holders nor the names
     23  *    of any contributors may be used to endorse or promote products derived
     24  *    from this software without specific prior written permission.
     25  *
     26  * Alternatively, this software may be distributed under the terms of the
     27  * GNU General Public License ("GPL") version 2 as published by the Free
     28  * Software Foundation.
     29  *
     30  * NO WARRANTY
     31  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     32  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     33  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
     34  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     35  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     36  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     37  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     38  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
     39  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
     40  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     41  * POSSIBILITY OF SUCH DAMAGES.
     42  */
     43 
     44 #include "acpi.h"
     45 #include "accommon.h"
     46 #include "acparser.h"
     47 #include "amlcode.h"
     48 #include "acdebug.h"
     49 
     50 
     51 #define _COMPONENT          ACPI_CA_DEBUGGER
     52         ACPI_MODULE_NAME    ("dmcstyle")
     53 
     54 
     55 /* Local prototypes */
     56 
     57 static const char *
     58 AcpiDmGetCompoundSymbol (
     59    UINT16                   AslOpcode);
     60 
     61 static void
     62 AcpiDmPromoteTarget (
     63     ACPI_PARSE_OBJECT       *Op,
     64     ACPI_PARSE_OBJECT       *Target);
     65 
     66 static BOOLEAN
     67 AcpiDmIsValidTarget (
     68     ACPI_PARSE_OBJECT       *Op);
     69 
     70 static BOOLEAN
     71 AcpiDmIsTargetAnOperand (
     72     ACPI_PARSE_OBJECT       *Target,
     73     ACPI_PARSE_OBJECT       *Operand,
     74     BOOLEAN                 TopLevel);
     75 
     76 
     77 /*******************************************************************************
     78  *
     79  * FUNCTION:    AcpiDmCheckForSymbolicOpcode
     80  *
     81  * PARAMETERS:  Op                  - Current parse object
     82  *              Walk                - Current parse tree walk info
     83  *
     84  * RETURN:      TRUE if opcode can be converted to symbolic, FALSE otherwise
     85  *
     86  * DESCRIPTION: This is the main code that implements disassembly of AML code
     87  *              to C-style operators. Called during descending phase of the
     88  *              parse tree walk.
     89  *
     90  ******************************************************************************/
     91 
     92 BOOLEAN
     93 AcpiDmCheckForSymbolicOpcode (
     94     ACPI_PARSE_OBJECT       *Op,
     95     ACPI_OP_WALK_INFO       *Info)
     96 {
     97     const char              *OperatorSymbol = NULL;
     98     ACPI_PARSE_OBJECT       *Child1;
     99     ACPI_PARSE_OBJECT       *Child2;
    100     ACPI_PARSE_OBJECT       *Target;
    101     ACPI_PARSE_OBJECT       *GrandChild1;
    102     ACPI_PARSE_OBJECT       *GrandChild2;
    103     ACPI_PARSE_OBJECT       *GrandTarget = NULL;
    104 
    105 
    106     /* Exit immediately if ASL+ not enabled */
    107 
    108     if (!AcpiGbl_CstyleDisassembly)
    109     {
    110         return (FALSE);
    111     }
    112 
    113     /* Check for a non-ASL+ statement, propagate the flag */
    114 
    115     if (Op->Common.Parent->Common.DisasmFlags & ACPI_PARSEOP_LEGACY_ASL_ONLY)
    116     {
    117         Op->Common.DisasmFlags |= ACPI_PARSEOP_LEGACY_ASL_ONLY;
    118         return (FALSE);
    119     }
    120 
    121     /* Get the first operand */
    122 
    123     Child1 = AcpiPsGetArg (Op, 0);
    124     if (!Child1)
    125     {
    126         return (FALSE);
    127     }
    128 
    129     /* Get the second operand */
    130 
    131     Child2 = Child1->Common.Next;
    132 
    133     /* Setup the operator string for this opcode */
    134 
    135     switch (Op->Common.AmlOpcode)
    136     {
    137     case AML_ADD_OP:
    138         OperatorSymbol = " + ";
    139         break;
    140 
    141     case AML_SUBTRACT_OP:
    142         OperatorSymbol = " - ";
    143         break;
    144 
    145     case AML_MULTIPLY_OP:
    146         OperatorSymbol = " * ";
    147         break;
    148 
    149     case AML_DIVIDE_OP:
    150         OperatorSymbol = " / ";
    151         break;
    152 
    153     case AML_MOD_OP:
    154         OperatorSymbol = " % ";
    155         break;
    156 
    157     case AML_SHIFT_LEFT_OP:
    158         OperatorSymbol = " << ";
    159         break;
    160 
    161     case AML_SHIFT_RIGHT_OP:
    162         OperatorSymbol = " >> ";
    163         break;
    164 
    165     case AML_BIT_AND_OP:
    166         OperatorSymbol = " & ";
    167         break;
    168 
    169     case AML_BIT_OR_OP:
    170         OperatorSymbol = " | ";
    171         break;
    172 
    173     case AML_BIT_XOR_OP:
    174         OperatorSymbol = " ^ ";
    175         break;
    176 
    177     /* Logical operators, no target */
    178 
    179     case AML_LAND_OP:
    180         OperatorSymbol = " && ";
    181         break;
    182 
    183     case AML_LEQUAL_OP:
    184         OperatorSymbol = " == ";
    185         break;
    186 
    187     case AML_LGREATER_OP:
    188         OperatorSymbol = " > ";
    189         break;
    190 
    191     case AML_LLESS_OP:
    192         OperatorSymbol = " < ";
    193         break;
    194 
    195     case AML_LOR_OP:
    196         OperatorSymbol = " || ";
    197         break;
    198 
    199     case AML_LNOT_OP:
    200         /*
    201          * Check for the LNOT sub-opcodes. These correspond to
    202          * LNotEqual, LLessEqual, and LGreaterEqual. There are
    203          * no actual AML opcodes for these operators.
    204          */
    205         switch (Child1->Common.AmlOpcode)
    206         {
    207         case AML_LEQUAL_OP:
    208             OperatorSymbol = " != ";
    209             break;
    210 
    211         case AML_LGREATER_OP:
    212             OperatorSymbol = " <= ";
    213             break;
    214 
    215         case AML_LLESS_OP:
    216             OperatorSymbol = " >= ";
    217             break;
    218 
    219         default:
    220 
    221             /* Unary LNOT case, emit "!" immediately */
    222 
    223             AcpiOsPrintf ("!");
    224             return (TRUE);
    225         }
    226 
    227         Child1->Common.DisasmOpcode = ACPI_DASM_LNOT_SUFFIX;
    228         Op->Common.DisasmOpcode = ACPI_DASM_LNOT_PREFIX;
    229         Op->Common.DisasmFlags |= ACPI_PARSEOP_COMPOUND_ASSIGNMENT;
    230 
    231         /* Save symbol string in the next child (not peer) */
    232 
    233         Child2 = AcpiPsGetArg (Child1, 0);
    234         if (!Child2)
    235         {
    236             return (FALSE);
    237         }
    238 
    239         Child2->Common.OperatorSymbol = OperatorSymbol;
    240         return (TRUE);
    241 
    242     case AML_INDEX_OP:
    243         /*
    244          * Check for constant source operand. Note: although technically
    245          * legal syntax, the iASL compiler does not support this with
    246          * the symbolic operators for Index(). It doesn't make sense to
    247          * use Index() with a constant anyway.
    248          */
    249         if ((Child1->Common.AmlOpcode == AML_STRING_OP)  ||
    250             (Child1->Common.AmlOpcode == AML_BUFFER_OP)  ||
    251             (Child1->Common.AmlOpcode == AML_PACKAGE_OP) ||
    252             (Child1->Common.AmlOpcode == AML_VAR_PACKAGE_OP))
    253         {
    254             Op->Common.DisasmFlags |= ACPI_PARSEOP_CLOSING_PAREN;
    255             return (FALSE);
    256         }
    257 
    258         /* Index operator is [] */
    259 
    260         Child1->Common.OperatorSymbol = " [";
    261         Child2->Common.OperatorSymbol = "]";
    262         break;
    263 
    264     /* Unary operators */
    265 
    266     case AML_DECREMENT_OP:
    267         OperatorSymbol = "--";
    268         break;
    269 
    270     case AML_INCREMENT_OP:
    271         OperatorSymbol = "++";
    272         break;
    273 
    274     case AML_BIT_NOT_OP:
    275     case AML_STORE_OP:
    276         OperatorSymbol = NULL;
    277         break;
    278 
    279     default:
    280         return (FALSE);
    281     }
    282 
    283     if (Child1->Common.DisasmOpcode == ACPI_DASM_LNOT_SUFFIX)
    284     {
    285         return (TRUE);
    286     }
    287 
    288     /*
    289      * This is the key to how the disassembly of the C-style operators
    290      * works. We save the operator symbol in the first child, thus
    291      * deferring symbol output until after the first operand has been
    292      * emitted.
    293      */
    294     if (!Child1->Common.OperatorSymbol)
    295     {
    296         Child1->Common.OperatorSymbol = OperatorSymbol;
    297     }
    298 
    299     /*
    300      * Check for a valid target as the 3rd (or sometimes 2nd) operand
    301      *
    302      * Compound assignment operator support:
    303      * Attempt to optimize constructs of the form:
    304      *      Add (Local1, 0xFF, Local1)
    305      * to:
    306      *      Local1 += 0xFF
    307      *
    308      * Only the math operators and Store() have a target.
    309      * Logicals have no target.
    310      */
    311     switch (Op->Common.AmlOpcode)
    312     {
    313     case AML_ADD_OP:
    314     case AML_SUBTRACT_OP:
    315     case AML_MULTIPLY_OP:
    316     case AML_DIVIDE_OP:
    317     case AML_MOD_OP:
    318     case AML_SHIFT_LEFT_OP:
    319     case AML_SHIFT_RIGHT_OP:
    320     case AML_BIT_AND_OP:
    321     case AML_BIT_OR_OP:
    322     case AML_BIT_XOR_OP:
    323 
    324         /* Target is 3rd operand */
    325 
    326         Target = Child2->Common.Next;
    327         if (Op->Common.AmlOpcode == AML_DIVIDE_OP)
    328         {
    329             /*
    330              * Divide has an extra target operand (Remainder).
    331              * If this extra target is specified, it cannot be converted
    332              * to a C-style operator
    333              */
    334             if (AcpiDmIsValidTarget (Target))
    335             {
    336                 Child1->Common.OperatorSymbol = NULL;
    337                 Op->Common.DisasmFlags |= ACPI_PARSEOP_LEGACY_ASL_ONLY;
    338                 return (FALSE);
    339             }
    340 
    341             Target->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
    342             Target = Target->Common.Next;
    343         }
    344 
    345         /* Parser should ensure there is at least a placeholder target */
    346 
    347         if (!Target)
    348         {
    349             return (FALSE);
    350         }
    351 
    352         if (!AcpiDmIsValidTarget (Target))
    353         {
    354             if (Op->Common.Parent->Common.AmlOpcode == AML_STORE_OP)
    355             {
    356                 Op->Common.DisasmFlags = 0;
    357                 Child1->Common.OperatorSymbol = NULL;
    358                 return (FALSE);
    359             }
    360 
    361             /* Not a valid target (placeholder only, from parser) */
    362             break;
    363         }
    364 
    365         /*
    366          * Promote the target up to the first child in the parse
    367          * tree. This is done because the target will be output
    368          * first, in the form:
    369          *     <Target> = Operands...
    370          */
    371         AcpiDmPromoteTarget (Op, Target);
    372 
    373         /* Check operands for conversion to a "Compound Assignment" */
    374 
    375         switch (Op->Common.AmlOpcode)
    376         {
    377             /* Commutative operators */
    378 
    379         case AML_ADD_OP:
    380         case AML_MULTIPLY_OP:
    381         case AML_BIT_AND_OP:
    382         case AML_BIT_OR_OP:
    383         case AML_BIT_XOR_OP:
    384             /*
    385              * For the commutative operators, we can convert to a
    386              * compound statement only if at least one (either) operand
    387              * is the same as the target.
    388              *
    389              *      Add (A, B, A) --> A += B
    390              *      Add (B, A, A) --> A += B
    391              *      Add (B, C, A) --> A = (B + C)
    392              */
    393             if ((AcpiDmIsTargetAnOperand (Target, Child1, TRUE)) ||
    394                 (AcpiDmIsTargetAnOperand (Target, Child2, TRUE)))
    395             {
    396                 Target->Common.OperatorSymbol =
    397                     AcpiDmGetCompoundSymbol (Op->Common.AmlOpcode);
    398 
    399                 /* Convert operator to compound assignment */
    400 
    401                 Op->Common.DisasmFlags |= ACPI_PARSEOP_COMPOUND_ASSIGNMENT;
    402                 Child1->Common.OperatorSymbol = NULL;
    403                 return (TRUE);
    404             }
    405             break;
    406 
    407             /* Non-commutative operators */
    408 
    409         case AML_SUBTRACT_OP:
    410         case AML_DIVIDE_OP:
    411         case AML_MOD_OP:
    412         case AML_SHIFT_LEFT_OP:
    413         case AML_SHIFT_RIGHT_OP:
    414             /*
    415              * For the non-commutative operators, we can convert to a
    416              * compound statement only if the target is the same as the
    417              * first operand.
    418              *
    419              *      Subtract (A, B, A) --> A -= B
    420              *      Subtract (B, A, A) --> A = (B - A)
    421              */
    422             if ((AcpiDmIsTargetAnOperand (Target, Child1, TRUE)))
    423             {
    424                 Target->Common.OperatorSymbol =
    425                     AcpiDmGetCompoundSymbol (Op->Common.AmlOpcode);
    426 
    427                 /* Convert operator to compound assignment */
    428 
    429                 Op->Common.DisasmFlags |= ACPI_PARSEOP_COMPOUND_ASSIGNMENT;
    430                 Child1->Common.OperatorSymbol = NULL;
    431                 return (TRUE);
    432             }
    433             break;
    434 
    435         default:
    436             break;
    437         }
    438 
    439         /*
    440          * If we are within a C-style expression, emit an extra open
    441          * paren. Implemented by examining the parent op.
    442          */
    443         switch (Op->Common.Parent->Common.AmlOpcode)
    444         {
    445         case AML_ADD_OP:
    446         case AML_SUBTRACT_OP:
    447         case AML_MULTIPLY_OP:
    448         case AML_DIVIDE_OP:
    449         case AML_MOD_OP:
    450         case AML_SHIFT_LEFT_OP:
    451         case AML_SHIFT_RIGHT_OP:
    452         case AML_BIT_AND_OP:
    453         case AML_BIT_OR_OP:
    454         case AML_BIT_XOR_OP:
    455         case AML_LAND_OP:
    456         case AML_LEQUAL_OP:
    457         case AML_LGREATER_OP:
    458         case AML_LLESS_OP:
    459         case AML_LOR_OP:
    460 
    461             Op->Common.DisasmFlags |= ACPI_PARSEOP_ASSIGNMENT;
    462             AcpiOsPrintf ("(");
    463             break;
    464 
    465         default:
    466             break;
    467         }
    468 
    469         /* Normal output for ASL/AML operators with a target operand */
    470 
    471         Target->Common.OperatorSymbol = " = (";
    472         return (TRUE);
    473 
    474     /* Binary operators, no parens */
    475 
    476     case AML_DECREMENT_OP:
    477     case AML_INCREMENT_OP:
    478         return (TRUE);
    479 
    480     case AML_INDEX_OP:
    481 
    482         /* Target is optional, 3rd operand */
    483 
    484         Target = Child2->Common.Next;
    485         if (AcpiDmIsValidTarget (Target))
    486         {
    487             AcpiDmPromoteTarget (Op, Target);
    488 
    489             if (!Target->Common.OperatorSymbol)
    490             {
    491                 Target->Common.OperatorSymbol = " = ";
    492             }
    493         }
    494         return (TRUE);
    495 
    496     case AML_STORE_OP:
    497         /*
    498          * Target is the 2nd operand.
    499          * We know the target is valid, it is not optional.
    500          *
    501          * The following block implements "Ignore conversion if a store
    502          * is followed by a math/bit operator that has no target". Used
    503          * only for the ASL test suite.
    504          */
    505         if (!AcpiGbl_DoDisassemblerOptimizations)
    506         {
    507             switch (Child1->Common.AmlOpcode)
    508             {
    509             /* This operator has two operands and two targets */
    510 
    511             case AML_DIVIDE_OP:
    512 
    513                 GrandChild1 = Child1->Common.Value.Arg;
    514                 GrandChild2 = GrandChild1->Common.Next;
    515                 GrandTarget = GrandChild2->Common.Next;
    516 
    517                 if (GrandTarget && !AcpiDmIsValidTarget (GrandTarget))
    518                 {
    519                     Op->Common.DisasmFlags |= ACPI_PARSEOP_LEGACY_ASL_ONLY;
    520                     return (FALSE);
    521                 }
    522                 GrandTarget = GrandTarget->Common.Next;
    523                 break;
    524 
    525             case AML_ADD_OP:
    526             case AML_SUBTRACT_OP:
    527             case AML_MULTIPLY_OP:
    528             case AML_MOD_OP:
    529             case AML_SHIFT_LEFT_OP:
    530             case AML_SHIFT_RIGHT_OP:
    531             case AML_BIT_AND_OP:
    532             case AML_BIT_OR_OP:
    533             case AML_BIT_XOR_OP:
    534             case AML_INDEX_OP:
    535 
    536                 /* These operators have two operands and a target */
    537 
    538                 GrandChild1 = Child1->Common.Value.Arg;
    539                 GrandChild2 = GrandChild1->Common.Next;
    540                 GrandTarget = GrandChild2->Common.Next;
    541                 break;
    542 
    543             case AML_BIT_NOT_OP:
    544 
    545                 /* This operator has one operand and a target */
    546 
    547                 GrandChild1 = Child1->Common.Value.Arg;
    548                 GrandTarget = GrandChild1->Common.Next;
    549                 break;
    550 
    551             default:
    552                 break;
    553             }
    554 
    555             if (GrandTarget && !AcpiDmIsValidTarget (GrandTarget))
    556             {
    557                 Op->Common.DisasmFlags |= ACPI_PARSEOP_LEGACY_ASL_ONLY;
    558                 return (FALSE);
    559             }
    560         }
    561 
    562         /*
    563          * In the parse tree, simply swap the target with the
    564          * source so that the target is processed first.
    565          */
    566         Target = Child1->Common.Next;
    567         if (!Target)
    568         {
    569             return (FALSE);
    570         }
    571 
    572         AcpiDmPromoteTarget (Op, Target);
    573         if (!Target->Common.OperatorSymbol)
    574         {
    575             Target->Common.OperatorSymbol = " = ";
    576         }
    577         return (TRUE);
    578 
    579     case AML_BIT_NOT_OP:
    580 
    581         /* Target is optional, 2nd operand */
    582 
    583         Target = Child1->Common.Next;
    584         if (!Target)
    585         {
    586             return (FALSE);
    587         }
    588 
    589         if (AcpiDmIsValidTarget (Target))
    590         {
    591             /* Valid target, not a placeholder */
    592 
    593             AcpiDmPromoteTarget (Op, Target);
    594             Target->Common.OperatorSymbol = " = ~";
    595         }
    596         else
    597         {
    598             /* No target. Emit this prefix operator immediately */
    599 
    600             AcpiOsPrintf ("~");
    601         }
    602         return (TRUE);
    603 
    604     default:
    605         break;
    606     }
    607 
    608     /*
    609      * Nodes marked with ACPI_PARSEOP_PARAMLIST don't need a parens
    610      * output here. We also need to check the parent to see if this op
    611      * is part of a compound test (!=, >=, <=).
    612      */
    613     if ((Op->Common.DisasmFlags & ACPI_PARSEOP_PARAMETER_LIST) ||
    614        ((Op->Common.Parent->Common.DisasmFlags & ACPI_PARSEOP_PARAMETER_LIST) &&
    615         (Op->Common.DisasmOpcode == ACPI_DASM_LNOT_SUFFIX)))
    616     {
    617         /* Do Nothing. Paren already generated */
    618         return (TRUE);
    619     }
    620 
    621     /* All other operators, emit an open paren */
    622 
    623     AcpiOsPrintf ("(");
    624     return (TRUE);
    625 }
    626 
    627 
    628 /*******************************************************************************
    629  *
    630  * FUNCTION:    AcpiDmCloseOperator
    631  *
    632  * PARAMETERS:  Op                  - Current parse object
    633  *
    634  * RETURN:      None
    635  *
    636  * DESCRIPTION: Closes an operator by adding a closing parentheses if and
    637  *              when necessary. Called during ascending phase of the
    638  *              parse tree walk.
    639  *
    640  ******************************************************************************/
    641 
    642 void
    643 AcpiDmCloseOperator (
    644     ACPI_PARSE_OBJECT       *Op)
    645 {
    646     BOOLEAN                 IsCStyleOp = FALSE;
    647 
    648 
    649     /* Always emit paren if ASL+ disassembly disabled */
    650 
    651     if (!AcpiGbl_CstyleDisassembly)
    652     {
    653         AcpiOsPrintf (")");
    654         return;
    655     }
    656 
    657     /* Check for a non-ASL+ statement */
    658 
    659     if (Op->Common.DisasmFlags & ACPI_PARSEOP_LEGACY_ASL_ONLY)
    660     {
    661         AcpiOsPrintf (")");
    662         return;
    663     }
    664 
    665     /* Check if we need to add an additional closing paren */
    666 
    667     switch (Op->Common.AmlOpcode)
    668     {
    669     case AML_ADD_OP:
    670     case AML_SUBTRACT_OP:
    671     case AML_MULTIPLY_OP:
    672     case AML_DIVIDE_OP:
    673     case AML_MOD_OP:
    674     case AML_SHIFT_LEFT_OP:
    675     case AML_SHIFT_RIGHT_OP:
    676     case AML_BIT_AND_OP:
    677     case AML_BIT_OR_OP:
    678     case AML_BIT_XOR_OP:
    679     case AML_LAND_OP:
    680     case AML_LEQUAL_OP:
    681     case AML_LGREATER_OP:
    682     case AML_LLESS_OP:
    683     case AML_LOR_OP:
    684 
    685         /* Emit paren only if this is not a compound assignment */
    686 
    687         if (Op->Common.DisasmFlags & ACPI_PARSEOP_COMPOUND_ASSIGNMENT)
    688         {
    689             return;
    690         }
    691 
    692         /* Emit extra close paren for assignment within an expression */
    693 
    694         if (Op->Common.DisasmFlags & ACPI_PARSEOP_ASSIGNMENT)
    695         {
    696             AcpiOsPrintf (")");
    697         }
    698 
    699         IsCStyleOp = TRUE;
    700         break;
    701 
    702     case AML_INDEX_OP:
    703 
    704         /* This is case for unsupported Index() source constants */
    705 
    706         if (Op->Common.DisasmFlags & ACPI_PARSEOP_CLOSING_PAREN)
    707         {
    708             AcpiOsPrintf (")");
    709         }
    710         return;
    711 
    712     /* No need for parens for these */
    713 
    714     case AML_DECREMENT_OP:
    715     case AML_INCREMENT_OP:
    716     case AML_LNOT_OP:
    717     case AML_BIT_NOT_OP:
    718     case AML_STORE_OP:
    719         return;
    720 
    721     default:
    722 
    723         /* Always emit paren for non-ASL+ operators */
    724         break;
    725     }
    726 
    727     /*
    728      * Nodes marked with ACPI_PARSEOP_PARAMLIST don't need a parens
    729      * output here. We also need to check the parent to see if this op
    730      * is part of a compound test (!=, >=, <=).
    731      */
    732     if (IsCStyleOp &&
    733        ((Op->Common.DisasmFlags & ACPI_PARSEOP_PARAMETER_LIST) ||
    734        ((Op->Common.Parent->Common.DisasmFlags & ACPI_PARSEOP_PARAMETER_LIST) &&
    735         (Op->Common.DisasmOpcode == ACPI_DASM_LNOT_SUFFIX))))
    736     {
    737         return;
    738     }
    739 
    740     AcpiOsPrintf (")");
    741     return;
    742 }
    743 
    744 
    745 /*******************************************************************************
    746  *
    747  * FUNCTION:    AcpiDmGetCompoundSymbol
    748  *
    749  * PARAMETERS:  AslOpcode
    750  *
    751  * RETURN:      String containing the compound assignment symbol
    752  *
    753  * DESCRIPTION: Detect opcodes that can be converted to compound assignment,
    754  *              return the appropriate operator string.
    755  *
    756  ******************************************************************************/
    757 
    758 static const char *
    759 AcpiDmGetCompoundSymbol (
    760    UINT16                   AmlOpcode)
    761 {
    762     const char               *Symbol;
    763 
    764 
    765     switch (AmlOpcode)
    766     {
    767     case AML_ADD_OP:
    768         Symbol = " += ";
    769         break;
    770 
    771     case AML_SUBTRACT_OP:
    772         Symbol = " -= ";
    773         break;
    774 
    775     case AML_MULTIPLY_OP:
    776         Symbol = " *= ";
    777         break;
    778 
    779     case AML_DIVIDE_OP:
    780         Symbol = " /= ";
    781         break;
    782 
    783     case AML_MOD_OP:
    784         Symbol = " %= ";
    785         break;
    786 
    787     case AML_SHIFT_LEFT_OP:
    788         Symbol = " <<= ";
    789         break;
    790 
    791     case AML_SHIFT_RIGHT_OP:
    792         Symbol = " >>= ";
    793         break;
    794 
    795     case AML_BIT_AND_OP:
    796         Symbol = " &= ";
    797         break;
    798 
    799     case AML_BIT_OR_OP:
    800         Symbol = " |= ";
    801         break;
    802 
    803     case AML_BIT_XOR_OP:
    804         Symbol = " ^= ";
    805         break;
    806 
    807     default:
    808 
    809         /* No operator string for all other opcodes */
    810 
    811         return (NULL);
    812     }
    813 
    814     return (Symbol);
    815 }
    816 
    817 
    818 /*******************************************************************************
    819  *
    820  * FUNCTION:    AcpiDmPromoteTarget
    821  *
    822  * PARAMETERS:  Op                  - Operator parse object
    823  *              Target              - Target associate with the Op
    824  *
    825  * RETURN:      None
    826  *
    827  * DESCRIPTION: Transform the parse tree by moving the target up to the first
    828  *              child of the Op.
    829  *
    830  ******************************************************************************/
    831 
    832 static void
    833 AcpiDmPromoteTarget (
    834     ACPI_PARSE_OBJECT       *Op,
    835     ACPI_PARSE_OBJECT       *Target)
    836 {
    837     ACPI_PARSE_OBJECT       *Child;
    838 
    839 
    840     /* Link target directly to the Op as first child */
    841 
    842     Child = Op->Common.Value.Arg;
    843     Op->Common.Value.Arg = Target;
    844     Target->Common.Next = Child;
    845 
    846     /* Find the last peer, it is linked to the target. Unlink it. */
    847 
    848     while (Child->Common.Next != Target)
    849     {
    850         Child = Child->Common.Next;
    851     }
    852 
    853     Child->Common.Next = NULL;
    854 }
    855 
    856 
    857 /*******************************************************************************
    858  *
    859  * FUNCTION:    AcpiDmIsValidTarget
    860  *
    861  * PARAMETERS:  Target              - Target Op from the parse tree
    862  *
    863  * RETURN:      TRUE if the Target is real. FALSE if it is just a placeholder
    864  *              Op that was inserted by the parser.
    865  *
    866  * DESCRIPTION: Determine if a Target Op is a placeholder Op or a real Target.
    867  *              In other words, determine if the optional target is used or
    868  *              not. Note: If Target is NULL, something is seriously wrong,
    869  *              probably with the parse tree.
    870  *
    871  ******************************************************************************/
    872 
    873 static BOOLEAN
    874 AcpiDmIsValidTarget (
    875     ACPI_PARSE_OBJECT       *Target)
    876 {
    877 
    878     if (!Target)
    879     {
    880         return (FALSE);
    881     }
    882 
    883     if ((Target->Common.AmlOpcode == AML_INT_NAMEPATH_OP) &&
    884         (Target->Common.Value.Arg == NULL))
    885     {
    886         return (FALSE);
    887     }
    888 
    889     return (TRUE);
    890 }
    891 
    892 
    893 /*******************************************************************************
    894  *
    895  * FUNCTION:    AcpiDmIsTargetAnOperand
    896  *
    897  * PARAMETERS:  Target              - Target associated with the expression
    898  *              Operand             - An operand associated with expression
    899  *
    900  * RETURN:      TRUE if expression can be converted to a compound assignment.
    901  *              FALSE otherwise.
    902  *
    903  * DESCRIPTION: Determine if the Target duplicates the operand, in order to
    904  *              detect if the expression can be converted to a compound
    905  *              assigment. (+=, *=, etc.)
    906  *
    907  ******************************************************************************/
    908 
    909 static BOOLEAN
    910 AcpiDmIsTargetAnOperand (
    911     ACPI_PARSE_OBJECT       *Target,
    912     ACPI_PARSE_OBJECT       *Operand,
    913     BOOLEAN                 TopLevel)
    914 {
    915     const ACPI_OPCODE_INFO  *OpInfo;
    916     BOOLEAN                 Same;
    917 
    918 
    919     /*
    920      * Opcodes must match. Note: ignoring the difference between nameseg
    921      * and namepath for now. May be needed later.
    922      */
    923     if (Target->Common.AmlOpcode != Operand->Common.AmlOpcode)
    924     {
    925         return (FALSE);
    926     }
    927 
    928     /* Nodes should match, even if they are NULL */
    929 
    930     if (Target->Common.Node != Operand->Common.Node)
    931     {
    932         return (FALSE);
    933     }
    934 
    935     /* Determine if a child exists */
    936 
    937     OpInfo = AcpiPsGetOpcodeInfo (Operand->Common.AmlOpcode);
    938     if (OpInfo->Flags & AML_HAS_ARGS)
    939     {
    940         Same = AcpiDmIsTargetAnOperand (Target->Common.Value.Arg,
    941             Operand->Common.Value.Arg, FALSE);
    942         if (!Same)
    943         {
    944             return (FALSE);
    945         }
    946     }
    947 
    948     /* Check the next peer, as long as we are not at the top level */
    949 
    950     if ((!TopLevel) &&
    951          Target->Common.Next)
    952     {
    953         Same = AcpiDmIsTargetAnOperand (Target->Common.Next,
    954             Operand->Common.Next, FALSE);
    955         if (!Same)
    956         {
    957             return (FALSE);
    958         }
    959     }
    960 
    961     /* Supress the duplicate operand at the top-level */
    962 
    963     if (TopLevel)
    964     {
    965         Operand->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
    966     }
    967     return (TRUE);
    968 }
    969