Home | History | Annotate | Line # | Download | only in disassembler
dmcstyle.c revision 1.13
      1 /*******************************************************************************
      2  *
      3  * Module Name: dmcstyle - Support for C-style operator disassembly
      4  *
      5  ******************************************************************************/
      6 
      7 /*
      8  * Copyright (C) 2000 - 2021, 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 MERCHANTABILITY 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 #include "acconvert.h"
     50 
     51 
     52 #define _COMPONENT          ACPI_CA_DEBUGGER
     53         ACPI_MODULE_NAME    ("dmcstyle")
     54 
     55 
     56 /* Local prototypes */
     57 
     58 static const char *
     59 AcpiDmGetCompoundSymbol (
     60    UINT16                   AslOpcode);
     61 
     62 static void
     63 AcpiDmPromoteTarget (
     64     ACPI_PARSE_OBJECT       *Op,
     65     ACPI_PARSE_OBJECT       *Target);
     66 
     67 static BOOLEAN
     68 AcpiDmIsValidTarget (
     69     ACPI_PARSE_OBJECT       *Op);
     70 
     71 static BOOLEAN
     72 AcpiDmIsTargetAnOperand (
     73     ACPI_PARSE_OBJECT       *Target,
     74     ACPI_PARSE_OBJECT       *Operand,
     75     BOOLEAN                 TopLevel);
     76 
     77 static BOOLEAN
     78 AcpiDmIsOptimizationIgnored (
     79     ACPI_PARSE_OBJECT       *StoreOp,
     80     ACPI_PARSE_OBJECT       *StoreArgument);
     81 
     82 
     83 /*******************************************************************************
     84  *
     85  * FUNCTION:    AcpiDmCheckForSymbolicOpcode
     86  *
     87  * PARAMETERS:  Op                  - Current parse object
     88  *              Walk                - Current parse tree walk info
     89  *
     90  * RETURN:      TRUE if opcode can be converted to symbolic, FALSE otherwise
     91  *
     92  * DESCRIPTION: This is the main code that implements disassembly of AML code
     93  *              to C-style operators. Called during descending phase of the
     94  *              parse tree walk.
     95  *
     96  ******************************************************************************/
     97 
     98 BOOLEAN
     99 AcpiDmCheckForSymbolicOpcode (
    100     ACPI_PARSE_OBJECT       *Op,
    101     ACPI_OP_WALK_INFO       *Info)
    102 {
    103     const char              *OperatorSymbol = NULL;
    104     ACPI_PARSE_OBJECT       *Argument1;
    105     ACPI_PARSE_OBJECT       *Argument2;
    106     ACPI_PARSE_OBJECT       *Target;
    107     ACPI_PARSE_OBJECT       *Target2;
    108 
    109 
    110     /* Exit immediately if ASL+ not enabled */
    111 
    112     if (!AcpiGbl_CstyleDisassembly)
    113     {
    114         return (FALSE);
    115     }
    116 
    117     /* Get the first operand */
    118 
    119     Argument1 = AcpiPsGetArg (Op, 0);
    120     if (!Argument1)
    121     {
    122         return (FALSE);
    123     }
    124 
    125     /* Get the second operand */
    126 
    127     Argument2 = Argument1->Common.Next;
    128 
    129     /* Setup the operator string for this opcode */
    130 
    131     switch (Op->Common.AmlOpcode)
    132     {
    133     case AML_ADD_OP:
    134         OperatorSymbol = " + ";
    135         break;
    136 
    137     case AML_SUBTRACT_OP:
    138         OperatorSymbol = " - ";
    139         break;
    140 
    141     case AML_MULTIPLY_OP:
    142         OperatorSymbol = " * ";
    143         break;
    144 
    145     case AML_DIVIDE_OP:
    146         OperatorSymbol = " / ";
    147         break;
    148 
    149     case AML_MOD_OP:
    150         OperatorSymbol = " % ";
    151         break;
    152 
    153     case AML_SHIFT_LEFT_OP:
    154         OperatorSymbol = " << ";
    155         break;
    156 
    157     case AML_SHIFT_RIGHT_OP:
    158         OperatorSymbol = " >> ";
    159         break;
    160 
    161     case AML_BIT_AND_OP:
    162         OperatorSymbol = " & ";
    163         break;
    164 
    165     case AML_BIT_OR_OP:
    166         OperatorSymbol = " | ";
    167         break;
    168 
    169     case AML_BIT_XOR_OP:
    170         OperatorSymbol = " ^ ";
    171         break;
    172 
    173     /* Logical operators, no target */
    174 
    175     case AML_LOGICAL_AND_OP:
    176         OperatorSymbol = " && ";
    177         break;
    178 
    179     case AML_LOGICAL_EQUAL_OP:
    180         OperatorSymbol = " == ";
    181         break;
    182 
    183     case AML_LOGICAL_GREATER_OP:
    184         OperatorSymbol = " > ";
    185         break;
    186 
    187     case AML_LOGICAL_LESS_OP:
    188         OperatorSymbol = " < ";
    189         break;
    190 
    191     case AML_LOGICAL_OR_OP:
    192         OperatorSymbol = " || ";
    193         break;
    194 
    195     case AML_LOGICAL_NOT_OP:
    196         /*
    197          * Check for the LNOT sub-opcodes. These correspond to
    198          * LNotEqual, LLessEqual, and LGreaterEqual. There are
    199          * no actual AML opcodes for these operators.
    200          */
    201         switch (Argument1->Common.AmlOpcode)
    202         {
    203         case AML_LOGICAL_EQUAL_OP:
    204             OperatorSymbol = " != ";
    205             break;
    206 
    207         case AML_LOGICAL_GREATER_OP:
    208             OperatorSymbol = " <= ";
    209             break;
    210 
    211         case AML_LOGICAL_LESS_OP:
    212             OperatorSymbol = " >= ";
    213             break;
    214 
    215         default:
    216 
    217             /* Unary LNOT case, emit "!" immediately */
    218 
    219             AcpiOsPrintf ("!");
    220             return (TRUE);
    221         }
    222 
    223         Argument1->Common.DisasmOpcode = ACPI_DASM_LNOT_SUFFIX;
    224         Op->Common.DisasmOpcode = ACPI_DASM_LNOT_PREFIX;
    225 
    226         /* Save symbol string in the next child (not peer) */
    227 
    228         Argument2 = AcpiPsGetArg (Argument1, 0);
    229         if (!Argument2)
    230         {
    231             return (FALSE);
    232         }
    233 
    234         Argument2->Common.OperatorSymbol = OperatorSymbol;
    235         return (TRUE);
    236 
    237     case AML_INDEX_OP:
    238         /*
    239          * Check for constant source operand. Note: although technically
    240          * legal syntax, the iASL compiler does not support this with
    241          * the symbolic operators for Index(). It doesn't make sense to
    242          * use Index() with a constant anyway.
    243          */
    244         if ((Argument1->Common.AmlOpcode == AML_STRING_OP)  ||
    245             (Argument1->Common.AmlOpcode == AML_BUFFER_OP)  ||
    246             (Argument1->Common.AmlOpcode == AML_PACKAGE_OP) ||
    247             (Argument1->Common.AmlOpcode == AML_VARIABLE_PACKAGE_OP))
    248         {
    249             Op->Common.DisasmFlags |= ACPI_PARSEOP_CLOSING_PAREN;
    250             return (FALSE);
    251         }
    252 
    253         /* Index operator is [] */
    254 
    255         Argument1->Common.OperatorSymbol = " [";
    256         Argument2->Common.OperatorSymbol = "]";
    257         break;
    258 
    259     /* Unary operators */
    260 
    261     case AML_DECREMENT_OP:
    262         OperatorSymbol = "--";
    263         break;
    264 
    265     case AML_INCREMENT_OP:
    266         OperatorSymbol = "++";
    267         break;
    268 
    269     case AML_BIT_NOT_OP:
    270     case AML_STORE_OP:
    271         OperatorSymbol = NULL;
    272         break;
    273 
    274     default:
    275         return (FALSE);
    276     }
    277 
    278     if (Argument1->Common.DisasmOpcode == ACPI_DASM_LNOT_SUFFIX)
    279     {
    280         return (TRUE);
    281     }
    282 
    283     /*
    284      * This is the key to how the disassembly of the C-style operators
    285      * works. We save the operator symbol in the first child, thus
    286      * deferring symbol output until after the first operand has been
    287      * emitted.
    288      */
    289     if (!Argument1->Common.OperatorSymbol)
    290     {
    291         Argument1->Common.OperatorSymbol = OperatorSymbol;
    292     }
    293 
    294     /*
    295      * Check for a valid target as the 3rd (or sometimes 2nd) operand
    296      *
    297      * Compound assignment operator support:
    298      * Attempt to optimize constructs of the form:
    299      *      Add (Local1, 0xFF, Local1)
    300      * to:
    301      *      Local1 += 0xFF
    302      *
    303      * Only the math operators and Store() have a target.
    304      * Logicals have no target.
    305      */
    306     switch (Op->Common.AmlOpcode)
    307     {
    308     case AML_ADD_OP:
    309     case AML_SUBTRACT_OP:
    310     case AML_MULTIPLY_OP:
    311     case AML_DIVIDE_OP:
    312     case AML_MOD_OP:
    313     case AML_SHIFT_LEFT_OP:
    314     case AML_SHIFT_RIGHT_OP:
    315     case AML_BIT_AND_OP:
    316     case AML_BIT_OR_OP:
    317     case AML_BIT_XOR_OP:
    318 
    319         /* Target is 3rd operand */
    320 
    321         Target = Argument2->Common.Next;
    322         if (Op->Common.AmlOpcode == AML_DIVIDE_OP)
    323         {
    324             Target2 = Target->Common.Next;
    325 
    326             /*
    327              * Divide has an extra target operand (Remainder).
    328              * Default behavior is to simply ignore ASL+ conversion
    329              * if the remainder target (modulo) is specified.
    330              */
    331             if (!AcpiGbl_DoDisassemblerOptimizations)
    332             {
    333                 if (AcpiDmIsValidTarget (Target))
    334                 {
    335                     Argument1->Common.OperatorSymbol = NULL;
    336                     Op->Common.DisasmFlags |= ACPI_PARSEOP_LEGACY_ASL_ONLY;
    337                     return (FALSE);
    338                 }
    339 
    340                 Target->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
    341                 Target = Target2;
    342             }
    343             else
    344             {
    345                 /*
    346                  * Divide has an extra target operand (Remainder).
    347                  * If both targets are specified, it cannot be converted
    348                  * to a C-style operator.
    349                  */
    350                 if (AcpiDmIsValidTarget (Target) &&
    351                     AcpiDmIsValidTarget (Target2))
    352                 {
    353                     Argument1->Common.OperatorSymbol = NULL;
    354                     Op->Common.DisasmFlags |= ACPI_PARSEOP_LEGACY_ASL_ONLY;
    355                     return (FALSE);
    356                 }
    357 
    358                 if (AcpiDmIsValidTarget (Target)) /* Only first Target is valid (remainder) */
    359                 {
    360                     /* Convert the Divide to Modulo */
    361 
    362                     Op->Common.AmlOpcode = AML_MOD_OP;
    363 
    364                     Argument1->Common.OperatorSymbol = " % ";
    365                     Target2->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
    366                 }
    367                 else /* Only second Target (quotient) is valid */
    368                 {
    369                     Target->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
    370                     Target = Target2;
    371                 }
    372             }
    373         }
    374 
    375         /* Parser should ensure there is at least a placeholder target */
    376 
    377         if (!Target)
    378         {
    379             return (FALSE);
    380         }
    381 
    382         if (!AcpiDmIsValidTarget (Target))
    383         {
    384             /* Not a valid target (placeholder only, from parser) */
    385             break;
    386         }
    387 
    388         /*
    389          * Promote the target up to the first child in the parse
    390          * tree. This is done because the target will be output
    391          * first, in the form:
    392          *     <Target> = Operands...
    393          */
    394         AcpiDmPromoteTarget (Op, Target);
    395 
    396         /* Check operands for conversion to a "Compound Assignment" */
    397 
    398         switch (Op->Common.AmlOpcode)
    399         {
    400             /* Commutative operators */
    401 
    402         case AML_ADD_OP:
    403         case AML_MULTIPLY_OP:
    404         case AML_BIT_AND_OP:
    405         case AML_BIT_OR_OP:
    406         case AML_BIT_XOR_OP:
    407             /*
    408              * For the commutative operators, we can convert to a
    409              * compound statement only if at least one (either) operand
    410              * is the same as the target.
    411              *
    412              *      Add (A, B, A) --> A += B
    413              *      Add (B, A, A) --> A += B
    414              *      Add (B, C, A) --> A = (B + C)
    415              */
    416             if ((AcpiDmIsTargetAnOperand (Target, Argument1, TRUE)) ||
    417                 (AcpiDmIsTargetAnOperand (Target, Argument2, TRUE)))
    418             {
    419                 Target->Common.OperatorSymbol =
    420                     AcpiDmGetCompoundSymbol (Op->Common.AmlOpcode);
    421 
    422                 /* Convert operator to compound assignment */
    423 
    424                 Op->Common.DisasmFlags |= ACPI_PARSEOP_COMPOUND_ASSIGNMENT;
    425                 Argument1->Common.OperatorSymbol = NULL;
    426                 return (TRUE);
    427             }
    428             break;
    429 
    430             /* Non-commutative operators */
    431 
    432         case AML_SUBTRACT_OP:
    433         case AML_DIVIDE_OP:
    434         case AML_MOD_OP:
    435         case AML_SHIFT_LEFT_OP:
    436         case AML_SHIFT_RIGHT_OP:
    437             /*
    438              * For the non-commutative operators, we can convert to a
    439              * compound statement only if the target is the same as the
    440              * first operand.
    441              *
    442              *      Subtract (A, B, A) --> A -= B
    443              *      Subtract (B, A, A) --> A = (B - A)
    444              */
    445             if ((AcpiDmIsTargetAnOperand (Target, Argument1, TRUE)))
    446             {
    447                 Target->Common.OperatorSymbol =
    448                     AcpiDmGetCompoundSymbol (Op->Common.AmlOpcode);
    449 
    450                 /* Convert operator to compound assignment */
    451 
    452                 Op->Common.DisasmFlags |= ACPI_PARSEOP_COMPOUND_ASSIGNMENT;
    453                 Argument1->Common.OperatorSymbol = NULL;
    454                 return (TRUE);
    455             }
    456             break;
    457 
    458         default:
    459             break;
    460         }
    461 
    462         /*
    463          * If we are within a C-style expression, emit an extra open
    464          * paren. Implemented by examining the parent op.
    465          */
    466         switch (Op->Common.Parent->Common.AmlOpcode)
    467         {
    468         case AML_ADD_OP:
    469         case AML_SUBTRACT_OP:
    470         case AML_MULTIPLY_OP:
    471         case AML_DIVIDE_OP:
    472         case AML_MOD_OP:
    473         case AML_SHIFT_LEFT_OP:
    474         case AML_SHIFT_RIGHT_OP:
    475         case AML_BIT_AND_OP:
    476         case AML_BIT_OR_OP:
    477         case AML_BIT_XOR_OP:
    478         case AML_LOGICAL_AND_OP:
    479         case AML_LOGICAL_EQUAL_OP:
    480         case AML_LOGICAL_GREATER_OP:
    481         case AML_LOGICAL_LESS_OP:
    482         case AML_LOGICAL_OR_OP:
    483 
    484             Op->Common.DisasmFlags |= ACPI_PARSEOP_ASSIGNMENT;
    485             AcpiOsPrintf ("(");
    486             break;
    487 
    488         default:
    489             break;
    490         }
    491 
    492         /* Normal output for ASL/AML operators with a target operand */
    493 
    494         Target->Common.OperatorSymbol = " = (";
    495         return (TRUE);
    496 
    497     /* Binary operators, no parens */
    498 
    499     case AML_DECREMENT_OP:
    500     case AML_INCREMENT_OP:
    501         return (TRUE);
    502 
    503     case AML_INDEX_OP:
    504 
    505         /* Target is optional, 3rd operand */
    506 
    507         Target = Argument2->Common.Next;
    508         if (AcpiDmIsValidTarget (Target))
    509         {
    510             AcpiDmPromoteTarget (Op, Target);
    511 
    512             if (!Target->Common.OperatorSymbol)
    513             {
    514                 Target->Common.OperatorSymbol = " = ";
    515             }
    516         }
    517         return (TRUE);
    518 
    519     case AML_STORE_OP:
    520         /*
    521          * For Store, the Target is the 2nd operand. We know the target
    522          * is valid, because it is not optional.
    523          *
    524          * Ignore any optimizations/folding if flag is set.
    525          * Used for iASL/disassembler test suite only.
    526          */
    527         if (AcpiDmIsOptimizationIgnored (Op, Argument1))
    528         {
    529             return (FALSE);
    530         }
    531 
    532         /*
    533          * Perform conversion.
    534          * In the parse tree, simply swap the target with the
    535          * source so that the target is processed first.
    536          */
    537         Target = Argument1->Common.Next;
    538         if (!Target)
    539         {
    540             return (FALSE);
    541         }
    542 
    543         AcpiDmPromoteTarget (Op, Target);
    544         if (!Target->Common.OperatorSymbol)
    545         {
    546             Target->Common.OperatorSymbol = " = ";
    547         }
    548         return (TRUE);
    549 
    550     case AML_BIT_NOT_OP:
    551 
    552         /* Target is optional, 2nd operand */
    553 
    554         Target = Argument1->Common.Next;
    555         if (!Target)
    556         {
    557             return (FALSE);
    558         }
    559 
    560         if (AcpiDmIsValidTarget (Target))
    561         {
    562             /* Valid target, not a placeholder */
    563 
    564             AcpiDmPromoteTarget (Op, Target);
    565             Target->Common.OperatorSymbol = " = ~";
    566         }
    567         else
    568         {
    569             /* No target. Emit this prefix operator immediately */
    570 
    571             AcpiOsPrintf ("~");
    572         }
    573         return (TRUE);
    574 
    575     default:
    576         break;
    577     }
    578 
    579     /* All other operators, emit an open paren */
    580 
    581     AcpiOsPrintf ("(");
    582     return (TRUE);
    583 }
    584 
    585 
    586 /*******************************************************************************
    587  *
    588  * FUNCTION:    AcpiDmIsOptimizationIgnored
    589  *
    590  * PARAMETERS:  StoreOp             - Store operator parse object
    591  *              StoreArgument       - Target associate with the Op
    592  *
    593  * RETURN:      TRUE if this Store operator should not be converted/removed.
    594  *
    595  * DESCRIPTION: The following function implements "Do not optimize if a
    596  *              store is immediately followed by a math/bit operator that
    597  *              has no target".
    598  *
    599  *              Function is ignored if DoDisassemblerOptimizations is TRUE.
    600  *              This is the default, ignore this function.
    601  *
    602  *              Disables these types of optimizations, and simply emits
    603  *              legacy ASL code:
    604  *                  Store (Add (INT1, 4), INT2) --> Add (INT1, 4, INT2)
    605  *                                              --> INT2 = INT1 + 4
    606  *
    607  *                  Store (Not (INT1), INT2)    --> Not (INT1, INT2)
    608  *                                              --> INT2 = ~INT1
    609  *
    610  *              Used only for the ASL test suite. For the test suite, we
    611  *              don't want to perform some optimizations to ensure binary
    612  *              compatibility with the generation of the legacy ASL->AML.
    613  *              In other words, for all test modules we want exactly:
    614  *                  (ASL+ -> AML) == (ASL- -> AML)
    615  *
    616  ******************************************************************************/
    617 
    618 static BOOLEAN
    619 AcpiDmIsOptimizationIgnored (
    620     ACPI_PARSE_OBJECT       *StoreOp,
    621     ACPI_PARSE_OBJECT       *StoreArgument)
    622 {
    623     ACPI_PARSE_OBJECT       *Argument1;
    624     ACPI_PARSE_OBJECT       *Argument2;
    625     ACPI_PARSE_OBJECT       *Target;
    626 
    627 
    628     /* No optimizations/folding for the typical case */
    629 
    630     if (AcpiGbl_DoDisassemblerOptimizations)
    631     {
    632         return (FALSE);
    633     }
    634 
    635     /*
    636      * Only a small subset of ASL/AML operators can be optimized.
    637      * Can only optimize/fold if there is no target (or targets)
    638      * specified for the operator. And of course, the operator
    639      * is surrounded by a Store() operator.
    640      */
    641     switch (StoreArgument->Common.AmlOpcode)
    642     {
    643     case AML_ADD_OP:
    644     case AML_SUBTRACT_OP:
    645     case AML_MULTIPLY_OP:
    646     case AML_MOD_OP:
    647     case AML_SHIFT_LEFT_OP:
    648     case AML_SHIFT_RIGHT_OP:
    649     case AML_BIT_AND_OP:
    650     case AML_BIT_OR_OP:
    651     case AML_BIT_XOR_OP:
    652     case AML_INDEX_OP:
    653 
    654         /* These operators have two arguments and one target */
    655 
    656         Argument1 = StoreArgument->Common.Value.Arg;
    657         Argument2 = Argument1->Common.Next;
    658         Target = Argument2->Common.Next;
    659 
    660         if (!AcpiDmIsValidTarget (Target))
    661         {
    662             StoreOp->Common.DisasmFlags |= ACPI_PARSEOP_LEGACY_ASL_ONLY;
    663             return (TRUE);
    664         }
    665         break;
    666 
    667     case AML_DIVIDE_OP:
    668 
    669         /* This operator has two arguments and two targets */
    670 
    671         Argument1 = StoreArgument->Common.Value.Arg;
    672         Argument2 = Argument1->Common.Next;
    673         Target = Argument2->Common.Next;
    674 
    675         if (!AcpiDmIsValidTarget (Target) ||
    676             !AcpiDmIsValidTarget (Target->Common.Next))
    677         {
    678             StoreOp->Common.DisasmFlags |= ACPI_PARSEOP_LEGACY_ASL_ONLY;
    679             return (TRUE);
    680         }
    681         break;
    682 
    683     case AML_BIT_NOT_OP:
    684 
    685         /* This operator has one operand and one target */
    686 
    687         Argument1 = StoreArgument->Common.Value.Arg;
    688         Target = Argument1->Common.Next;
    689 
    690         if (!AcpiDmIsValidTarget (Target))
    691         {
    692             StoreOp->Common.DisasmFlags |= ACPI_PARSEOP_LEGACY_ASL_ONLY;
    693             return (TRUE);
    694         }
    695         break;
    696 
    697     default:
    698         break;
    699     }
    700 
    701     return (FALSE);
    702 }
    703 
    704 
    705 /*******************************************************************************
    706  *
    707  * FUNCTION:    AcpiDmCloseOperator
    708  *
    709  * PARAMETERS:  Op                  - Current parse object
    710  *
    711  * RETURN:      None
    712  *
    713  * DESCRIPTION: Closes an operator by adding a closing parentheses if and
    714  *              when necessary. Called during ascending phase of the
    715  *              parse tree walk.
    716  *
    717  ******************************************************************************/
    718 
    719 void
    720 AcpiDmCloseOperator (
    721     ACPI_PARSE_OBJECT       *Op)
    722 {
    723 
    724     /* Always emit paren if ASL+ disassembly disabled */
    725 
    726     if (!AcpiGbl_CstyleDisassembly)
    727     {
    728         AcpiOsPrintf (")");
    729         ASL_CV_PRINT_ONE_COMMENT (Op, AML_COMMENT_END_NODE, NULL, 0);
    730         return;
    731     }
    732 
    733     if (Op->Common.DisasmFlags & ACPI_PARSEOP_LEGACY_ASL_ONLY)
    734     {
    735         AcpiOsPrintf (")");
    736         ASL_CV_PRINT_ONE_COMMENT (Op, AML_COMMENT_END_NODE, NULL, 0);
    737         return;
    738     }
    739 
    740     /* Check if we need to add an additional closing paren */
    741 
    742     switch (Op->Common.AmlOpcode)
    743     {
    744     case AML_ADD_OP:
    745     case AML_SUBTRACT_OP:
    746     case AML_MULTIPLY_OP:
    747     case AML_DIVIDE_OP:
    748     case AML_MOD_OP:
    749     case AML_SHIFT_LEFT_OP:
    750     case AML_SHIFT_RIGHT_OP:
    751     case AML_BIT_AND_OP:
    752     case AML_BIT_OR_OP:
    753     case AML_BIT_XOR_OP:
    754     case AML_LOGICAL_AND_OP:
    755     case AML_LOGICAL_EQUAL_OP:
    756     case AML_LOGICAL_GREATER_OP:
    757     case AML_LOGICAL_LESS_OP:
    758     case AML_LOGICAL_OR_OP:
    759 
    760         /* Emit paren only if this is not a compound assignment */
    761 
    762         if (Op->Common.DisasmFlags & ACPI_PARSEOP_COMPOUND_ASSIGNMENT)
    763         {
    764             ASL_CV_PRINT_ONE_COMMENT (Op, AML_COMMENT_END_NODE, NULL, 0);
    765             return;
    766         }
    767 
    768         /* Emit extra close paren for assignment within an expression */
    769 
    770         if (Op->Common.DisasmFlags & ACPI_PARSEOP_ASSIGNMENT)
    771         {
    772             AcpiOsPrintf (")");
    773         }
    774         break;
    775 
    776     case AML_INDEX_OP:
    777 
    778         /* This is case for unsupported Index() source constants */
    779 
    780         if (Op->Common.DisasmFlags & ACPI_PARSEOP_CLOSING_PAREN)
    781         {
    782             AcpiOsPrintf (")");
    783         }
    784         ASL_CV_PRINT_ONE_COMMENT (Op, AML_COMMENT_END_NODE, NULL, 0);
    785         return;
    786 
    787     /* No need for parens for these */
    788 
    789     case AML_DECREMENT_OP:
    790     case AML_INCREMENT_OP:
    791     case AML_LOGICAL_NOT_OP:
    792     case AML_BIT_NOT_OP:
    793     case AML_STORE_OP:
    794         ASL_CV_PRINT_ONE_COMMENT (Op, AML_COMMENT_END_NODE, NULL, 0);
    795         return;
    796 
    797     default:
    798 
    799         /* Always emit paren for non-ASL+ operators */
    800         break;
    801     }
    802 
    803     AcpiOsPrintf (")");
    804     ASL_CV_PRINT_ONE_COMMENT (Op, AML_COMMENT_END_NODE, NULL, 0);
    805 
    806     return;
    807 }
    808 
    809 
    810 /*******************************************************************************
    811  *
    812  * FUNCTION:    AcpiDmGetCompoundSymbol
    813  *
    814  * PARAMETERS:  AslOpcode
    815  *
    816  * RETURN:      String containing the compound assignment symbol
    817  *
    818  * DESCRIPTION: Detect opcodes that can be converted to compound assignment,
    819  *              return the appropriate operator string.
    820  *
    821  ******************************************************************************/
    822 
    823 static const char *
    824 AcpiDmGetCompoundSymbol (
    825    UINT16                   AmlOpcode)
    826 {
    827     const char               *Symbol;
    828 
    829 
    830     switch (AmlOpcode)
    831     {
    832     case AML_ADD_OP:
    833         Symbol = " += ";
    834         break;
    835 
    836     case AML_SUBTRACT_OP:
    837         Symbol = " -= ";
    838         break;
    839 
    840     case AML_MULTIPLY_OP:
    841         Symbol = " *= ";
    842         break;
    843 
    844     case AML_DIVIDE_OP:
    845         Symbol = " /= ";
    846         break;
    847 
    848     case AML_MOD_OP:
    849         Symbol = " %= ";
    850         break;
    851 
    852     case AML_SHIFT_LEFT_OP:
    853         Symbol = " <<= ";
    854         break;
    855 
    856     case AML_SHIFT_RIGHT_OP:
    857         Symbol = " >>= ";
    858         break;
    859 
    860     case AML_BIT_AND_OP:
    861         Symbol = " &= ";
    862         break;
    863 
    864     case AML_BIT_OR_OP:
    865         Symbol = " |= ";
    866         break;
    867 
    868     case AML_BIT_XOR_OP:
    869         Symbol = " ^= ";
    870         break;
    871 
    872     default:
    873 
    874         /* No operator string for all other opcodes */
    875 
    876         return (NULL);
    877     }
    878 
    879     return (Symbol);
    880 }
    881 
    882 
    883 /*******************************************************************************
    884  *
    885  * FUNCTION:    AcpiDmPromoteTarget
    886  *
    887  * PARAMETERS:  Op                  - Operator parse object
    888  *              Target              - Target associate with the Op
    889  *
    890  * RETURN:      None
    891  *
    892  * DESCRIPTION: Transform the parse tree by moving the target up to the first
    893  *              child of the Op.
    894  *
    895  ******************************************************************************/
    896 
    897 static void
    898 AcpiDmPromoteTarget (
    899     ACPI_PARSE_OBJECT       *Op,
    900     ACPI_PARSE_OBJECT       *Target)
    901 {
    902     ACPI_PARSE_OBJECT       *Child;
    903 
    904 
    905     /* Link target directly to the Op as first child */
    906 
    907     Child = Op->Common.Value.Arg;
    908     Op->Common.Value.Arg = Target;
    909     Target->Common.Next = Child;
    910 
    911     /* Find the last peer, it is linked to the target. Unlink it. */
    912 
    913     while (Child->Common.Next != Target)
    914     {
    915         Child = Child->Common.Next;
    916     }
    917 
    918     Child->Common.Next = NULL;
    919 }
    920 
    921 
    922 /*******************************************************************************
    923  *
    924  * FUNCTION:    AcpiDmIsValidTarget
    925  *
    926  * PARAMETERS:  Target              - Target Op from the parse tree
    927  *
    928  * RETURN:      TRUE if the Target is real. FALSE if it is just a placeholder
    929  *              Op that was inserted by the parser.
    930  *
    931  * DESCRIPTION: Determine if a Target Op is a placeholder Op or a real Target.
    932  *              In other words, determine if the optional target is used or
    933  *              not. Note: If Target is NULL, something is seriously wrong,
    934  *              probably with the parse tree.
    935  *
    936  ******************************************************************************/
    937 
    938 static BOOLEAN
    939 AcpiDmIsValidTarget (
    940     ACPI_PARSE_OBJECT       *Target)
    941 {
    942 
    943     if (!Target)
    944     {
    945         return (FALSE);
    946     }
    947 
    948     if ((Target->Common.AmlOpcode == AML_INT_NAMEPATH_OP) &&
    949         (Target->Common.Value.Arg == NULL))
    950     {
    951         return (FALSE);
    952     }
    953 
    954     return (TRUE);
    955 }
    956 
    957 
    958 /*******************************************************************************
    959  *
    960  * FUNCTION:    AcpiDmIsTargetAnOperand
    961  *
    962  * PARAMETERS:  Target              - Target associated with the expression
    963  *              Operand             - An operand associated with expression
    964  *
    965  * RETURN:      TRUE if expression can be converted to a compound assignment.
    966  *              FALSE otherwise.
    967  *
    968  * DESCRIPTION: Determine if the Target duplicates the operand, in order to
    969  *              detect if the expression can be converted to a compound
    970  *              assignment. (+=, *=, etc.)
    971  *
    972  ******************************************************************************/
    973 
    974 static BOOLEAN
    975 AcpiDmIsTargetAnOperand (
    976     ACPI_PARSE_OBJECT       *Target,
    977     ACPI_PARSE_OBJECT       *Operand,
    978     BOOLEAN                 TopLevel)
    979 {
    980     const ACPI_OPCODE_INFO  *OpInfo;
    981     BOOLEAN                 Same;
    982 
    983 
    984     /*
    985      * Opcodes must match. Note: ignoring the difference between nameseg
    986      * and namepath for now. May be needed later.
    987      */
    988     if (Target->Common.AmlOpcode != Operand->Common.AmlOpcode)
    989     {
    990         return (FALSE);
    991     }
    992 
    993     /* Nodes should match, even if they are NULL */
    994 
    995     if (Target->Common.Node != Operand->Common.Node)
    996     {
    997         return (FALSE);
    998     }
    999 
   1000     /* Determine if a child exists */
   1001 
   1002     OpInfo = AcpiPsGetOpcodeInfo (Operand->Common.AmlOpcode);
   1003     if (OpInfo->Flags & AML_HAS_ARGS)
   1004     {
   1005         Same = AcpiDmIsTargetAnOperand (Target->Common.Value.Arg,
   1006             Operand->Common.Value.Arg, FALSE);
   1007         if (!Same)
   1008         {
   1009             return (FALSE);
   1010         }
   1011     }
   1012 
   1013     /* Check the next peer, as long as we are not at the top level */
   1014 
   1015     if ((!TopLevel) &&
   1016          Target->Common.Next)
   1017     {
   1018         Same = AcpiDmIsTargetAnOperand (Target->Common.Next,
   1019             Operand->Common.Next, FALSE);
   1020         if (!Same)
   1021         {
   1022             return (FALSE);
   1023         }
   1024     }
   1025 
   1026     /* Suppress the duplicate operand at the top-level */
   1027 
   1028     if (TopLevel)
   1029     {
   1030         Operand->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
   1031     }
   1032     return (TRUE);
   1033 }
   1034