Home | History | Annotate | Line # | Download | only in disassembler
dmcstyle.c revision 1.1.1.3
      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 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     char                    *OperatorSymbol = NULL;
     98     ACPI_PARSE_OBJECT       *Child1;
     99     ACPI_PARSE_OBJECT       *Child2;
    100     ACPI_PARSE_OBJECT       *Target;
    101 
    102 
    103     /* Exit immediately if ASL+ not enabled */
    104 
    105     if (!AcpiGbl_CstyleDisassembly)
    106     {
    107         return (FALSE);
    108     }
    109 
    110     /* Get the first operand */
    111 
    112     Child1 = AcpiPsGetArg (Op, 0);
    113     if (!Child1)
    114     {
    115         return (FALSE);
    116     }
    117 
    118     /* Get the second operand */
    119 
    120     Child2 = Child1->Common.Next;
    121 
    122     /* Setup the operator string for this opcode */
    123 
    124     switch (Op->Common.AmlOpcode)
    125     {
    126     case AML_ADD_OP:
    127         OperatorSymbol = " + ";
    128         break;
    129 
    130     case AML_SUBTRACT_OP:
    131         OperatorSymbol = " - ";
    132         break;
    133 
    134     case AML_MULTIPLY_OP:
    135         OperatorSymbol = " * ";
    136         break;
    137 
    138     case AML_DIVIDE_OP:
    139         OperatorSymbol = " / ";
    140         break;
    141 
    142     case AML_MOD_OP:
    143         OperatorSymbol = " % ";
    144         break;
    145 
    146     case AML_SHIFT_LEFT_OP:
    147         OperatorSymbol = " << ";
    148         break;
    149 
    150     case AML_SHIFT_RIGHT_OP:
    151         OperatorSymbol = " >> ";
    152         break;
    153 
    154     case AML_BIT_AND_OP:
    155         OperatorSymbol = " & ";
    156         break;
    157 
    158     case AML_BIT_OR_OP:
    159         OperatorSymbol = " | ";
    160         break;
    161 
    162     case AML_BIT_XOR_OP:
    163         OperatorSymbol = " ^ ";
    164         break;
    165 
    166     /* Logical operators, no target */
    167 
    168     case AML_LAND_OP:
    169         OperatorSymbol = " && ";
    170         break;
    171 
    172     case AML_LEQUAL_OP:
    173         OperatorSymbol = " == ";
    174         break;
    175 
    176     case AML_LGREATER_OP:
    177         OperatorSymbol = " > ";
    178         break;
    179 
    180     case AML_LLESS_OP:
    181         OperatorSymbol = " < ";
    182         break;
    183 
    184     case AML_LOR_OP:
    185         OperatorSymbol = " || ";
    186         break;
    187 
    188     case AML_LNOT_OP:
    189         /*
    190          * Check for the LNOT sub-opcodes. These correspond to
    191          * LNotEqual, LLessEqual, and LGreaterEqual. There are
    192          * no actual AML opcodes for these operators.
    193          */
    194         switch (Child1->Common.AmlOpcode)
    195         {
    196         case AML_LEQUAL_OP:
    197             OperatorSymbol = " != ";
    198             break;
    199 
    200         case AML_LGREATER_OP:
    201             OperatorSymbol = " <= ";
    202             break;
    203 
    204         case AML_LLESS_OP:
    205             OperatorSymbol = " >= ";
    206             break;
    207 
    208         default:
    209 
    210             /* Unary LNOT case, emit "!" immediately */
    211 
    212             AcpiOsPrintf ("!");
    213             return (TRUE);
    214         }
    215 
    216         Child1->Common.DisasmOpcode = ACPI_DASM_LNOT_SUFFIX;
    217         Op->Common.DisasmOpcode = ACPI_DASM_LNOT_PREFIX;
    218 
    219         /* Save symbol string in the next child (not peer) */
    220 
    221         Child2 = AcpiPsGetArg (Child1, 0);
    222         if (!Child2)
    223         {
    224             return (FALSE);
    225         }
    226 
    227         Child2->Common.OperatorSymbol = OperatorSymbol;
    228         return (TRUE);
    229 
    230     case AML_INDEX_OP:
    231         /*
    232          * Check for constant source operand. Note: although technically
    233          * legal syntax, the iASL compiler does not support this with
    234          * the symbolic operators for Index(). It doesn't make sense to
    235          * use Index() with a constant anyway.
    236          */
    237         if ((Child1->Common.AmlOpcode == AML_STRING_OP)  ||
    238             (Child1->Common.AmlOpcode == AML_BUFFER_OP)  ||
    239             (Child1->Common.AmlOpcode == AML_PACKAGE_OP) ||
    240             (Child1->Common.AmlOpcode == AML_VAR_PACKAGE_OP))
    241         {
    242             Op->Common.DisasmFlags |= ACPI_PARSEOP_CLOSING_PAREN;
    243             return (FALSE);
    244         }
    245 
    246         /* Index operator is [] */
    247 
    248         Child1->Common.OperatorSymbol = " [";
    249         Child2->Common.OperatorSymbol = "]";
    250         break;
    251 
    252     /* Unary operators */
    253 
    254     case AML_DECREMENT_OP:
    255         OperatorSymbol = "--";
    256         break;
    257 
    258     case AML_INCREMENT_OP:
    259         OperatorSymbol = "++";
    260         break;
    261 
    262     case AML_BIT_NOT_OP:
    263     case AML_STORE_OP:
    264         OperatorSymbol = NULL;
    265         break;
    266 
    267     default:
    268         return (FALSE);
    269     }
    270 
    271     if (Child1->Common.DisasmOpcode == ACPI_DASM_LNOT_SUFFIX)
    272     {
    273         return (TRUE);
    274     }
    275 
    276     /*
    277      * This is the key to how the disassembly of the C-style operators
    278      * works. We save the operator symbol in the first child, thus
    279      * deferring symbol output until after the first operand has been
    280      * emitted.
    281      */
    282     if (!Child1->Common.OperatorSymbol)
    283     {
    284         Child1->Common.OperatorSymbol = OperatorSymbol;
    285     }
    286 
    287     /*
    288      * Check for a valid target as the 3rd (or sometimes 2nd) operand
    289      *
    290      * Compound assignment operator support:
    291      * Attempt to optimize constructs of the form:
    292      *      Add (Local1, 0xFF, Local1)
    293      * to:
    294      *      Local1 += 0xFF
    295      *
    296      * Only the math operators and Store() have a target.
    297      * Logicals have no target.
    298      */
    299     switch (Op->Common.AmlOpcode)
    300     {
    301     case AML_ADD_OP:
    302     case AML_SUBTRACT_OP:
    303     case AML_MULTIPLY_OP:
    304     case AML_DIVIDE_OP:
    305     case AML_MOD_OP:
    306     case AML_SHIFT_LEFT_OP:
    307     case AML_SHIFT_RIGHT_OP:
    308     case AML_BIT_AND_OP:
    309     case AML_BIT_OR_OP:
    310     case AML_BIT_XOR_OP:
    311 
    312         /* Target is 3rd operand */
    313 
    314         Target = Child2->Common.Next;
    315         if (Op->Common.AmlOpcode == AML_DIVIDE_OP)
    316         {
    317             /*
    318              * Divide has an extra target operand (Remainder).
    319              * If this extra target is specified, it cannot be converted
    320              * to a C-style operator
    321              */
    322             if (AcpiDmIsValidTarget (Target))
    323             {
    324                 Child1->Common.OperatorSymbol = NULL;
    325                 return (FALSE);
    326             }
    327 
    328             Target->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
    329             Target = Target->Common.Next;
    330         }
    331 
    332         /* Parser should ensure there is at least a placeholder target */
    333 
    334         if (!Target)
    335         {
    336             return (FALSE);
    337         }
    338 
    339         if (!AcpiDmIsValidTarget (Target))
    340         {
    341             /* Not a valid target (placeholder only, from parser) */
    342             break;
    343         }
    344 
    345         /*
    346          * Promote the target up to the first child in the parse
    347          * tree. This is done because the target will be output
    348          * first, in the form:
    349          *     <Target> = Operands...
    350          */
    351         AcpiDmPromoteTarget (Op, Target);
    352 
    353         /* Check operands for conversion to a "Compound Assignment" */
    354 
    355         switch (Op->Common.AmlOpcode)
    356         {
    357             /* Commutative operators */
    358 
    359         case AML_ADD_OP:
    360         case AML_MULTIPLY_OP:
    361         case AML_BIT_AND_OP:
    362         case AML_BIT_OR_OP:
    363         case AML_BIT_XOR_OP:
    364             /*
    365              * For the commutative operators, we can convert to a
    366              * compound statement only if at least one (either) operand
    367              * is the same as the target.
    368              *
    369              *      Add (A, B, A) --> A += B
    370              *      Add (B, A, A) --> A += B
    371              *      Add (B, C, A) --> A = (B + C)
    372              */
    373             if ((AcpiDmIsTargetAnOperand (Target, Child1, TRUE)) ||
    374                 (AcpiDmIsTargetAnOperand (Target, Child2, TRUE)))
    375             {
    376                 Target->Common.OperatorSymbol =
    377                     AcpiDmGetCompoundSymbol (Op->Common.AmlOpcode);
    378 
    379                 /* Convert operator to compound assignment */
    380 
    381                 Op->Common.DisasmFlags |= ACPI_PARSEOP_COMPOUND;
    382                 Child1->Common.OperatorSymbol = NULL;
    383                 return (TRUE);
    384             }
    385             break;
    386 
    387             /* Non-commutative operators */
    388 
    389         case AML_SUBTRACT_OP:
    390         case AML_DIVIDE_OP:
    391         case AML_MOD_OP:
    392         case AML_SHIFT_LEFT_OP:
    393         case AML_SHIFT_RIGHT_OP:
    394             /*
    395              * For the non-commutative operators, we can convert to a
    396              * compound statement only if the target is the same as the
    397              * first operand.
    398              *
    399              *      Subtract (A, B, A) --> A -= B
    400              *      Subtract (B, A, A) --> A = (B - A)
    401              */
    402             if ((AcpiDmIsTargetAnOperand (Target, Child1, TRUE)))
    403             {
    404                 Target->Common.OperatorSymbol =
    405                     AcpiDmGetCompoundSymbol (Op->Common.AmlOpcode);
    406 
    407                 /* Convert operator to compound assignment */
    408 
    409                 Op->Common.DisasmFlags |= ACPI_PARSEOP_COMPOUND;
    410                 Child1->Common.OperatorSymbol = NULL;
    411                 return (TRUE);
    412             }
    413             break;
    414 
    415         default:
    416             break;
    417         }
    418 
    419         /*
    420          * If we are within a C-style expression, emit an extra open
    421          * paren. Implemented by examining the parent op.
    422          */
    423         switch (Op->Common.Parent->Common.AmlOpcode)
    424         {
    425         case AML_ADD_OP:
    426         case AML_SUBTRACT_OP:
    427         case AML_MULTIPLY_OP:
    428         case AML_DIVIDE_OP:
    429         case AML_MOD_OP:
    430         case AML_SHIFT_LEFT_OP:
    431         case AML_SHIFT_RIGHT_OP:
    432         case AML_BIT_AND_OP:
    433         case AML_BIT_OR_OP:
    434         case AML_BIT_XOR_OP:
    435         case AML_LAND_OP:
    436         case AML_LEQUAL_OP:
    437         case AML_LGREATER_OP:
    438         case AML_LLESS_OP:
    439         case AML_LOR_OP:
    440 
    441             Op->Common.DisasmFlags |= ACPI_PARSEOP_ASSIGNMENT;
    442             AcpiOsPrintf ("(");
    443             break;
    444 
    445         default:
    446             break;
    447         }
    448 
    449         /* Normal output for ASL/AML operators with a target operand */
    450 
    451         Target->Common.OperatorSymbol = " = (";
    452         return (TRUE);
    453 
    454     /* Binary operators, no parens */
    455 
    456     case AML_DECREMENT_OP:
    457     case AML_INCREMENT_OP:
    458         return (TRUE);
    459 
    460     case AML_INDEX_OP:
    461 
    462         /* Target is optional, 3rd operand */
    463 
    464         Target = Child2->Common.Next;
    465         if (AcpiDmIsValidTarget (Target))
    466         {
    467             AcpiDmPromoteTarget (Op, Target);
    468 
    469             if (!Target->Common.OperatorSymbol)
    470             {
    471                 Target->Common.OperatorSymbol = " = ";
    472             }
    473         }
    474         return (TRUE);
    475 
    476     case AML_STORE_OP:
    477         /*
    478          * Target is the 2nd operand.
    479          * We know the target is valid, it is not optional.
    480          * In the parse tree, simply swap the target with the
    481          * source so that the target is processed first.
    482          */
    483         Target = Child1->Common.Next;
    484         if (!Target)
    485         {
    486             return (FALSE);
    487         }
    488 
    489         AcpiDmPromoteTarget (Op, Target);
    490         if (!Target->Common.OperatorSymbol)
    491         {
    492             Target->Common.OperatorSymbol = " = ";
    493         }
    494         return (TRUE);
    495 
    496     case AML_BIT_NOT_OP:
    497 
    498         /* Target is optional, 2nd operand */
    499 
    500         Target = Child1->Common.Next;
    501         if (!Target)
    502         {
    503             return (FALSE);
    504         }
    505 
    506         if (AcpiDmIsValidTarget (Target))
    507         {
    508             /* Valid target, not a placeholder */
    509 
    510             AcpiDmPromoteTarget (Op, Target);
    511             Target->Common.OperatorSymbol = " = ~";
    512         }
    513         else
    514         {
    515             /* No target. Emit this prefix operator immediately */
    516 
    517             AcpiOsPrintf ("~");
    518         }
    519         return (TRUE);
    520 
    521     default:
    522         break;
    523     }
    524 
    525     /* All other operators, emit an open paren */
    526 
    527     AcpiOsPrintf ("(");
    528     return (TRUE);
    529 }
    530 
    531 
    532 /*******************************************************************************
    533  *
    534  * FUNCTION:    AcpiDmCloseOperator
    535  *
    536  * PARAMETERS:  Op                  - Current parse object
    537  *
    538  * RETURN:      None
    539  *
    540  * DESCRIPTION: Closes an operator by adding a closing parentheses if and
    541  *              when necessary. Called during ascending phase of the
    542  *              parse tree walk.
    543  *
    544  ******************************************************************************/
    545 
    546 void
    547 AcpiDmCloseOperator (
    548     ACPI_PARSE_OBJECT       *Op)
    549 {
    550 
    551     /* Always emit paren if ASL+ disassembly disabled */
    552 
    553     if (!AcpiGbl_CstyleDisassembly)
    554     {
    555         AcpiOsPrintf (")");
    556         return;
    557     }
    558 
    559     /* Check if we need to add an additional closing paren */
    560 
    561     switch (Op->Common.AmlOpcode)
    562     {
    563     case AML_ADD_OP:
    564     case AML_SUBTRACT_OP:
    565     case AML_MULTIPLY_OP:
    566     case AML_DIVIDE_OP:
    567     case AML_MOD_OP:
    568     case AML_SHIFT_LEFT_OP:
    569     case AML_SHIFT_RIGHT_OP:
    570     case AML_BIT_AND_OP:
    571     case AML_BIT_OR_OP:
    572     case AML_BIT_XOR_OP:
    573     case AML_LAND_OP:
    574     case AML_LEQUAL_OP:
    575     case AML_LGREATER_OP:
    576     case AML_LLESS_OP:
    577     case AML_LOR_OP:
    578 
    579         /* Emit paren only if this is not a compound assignment */
    580 
    581         if (Op->Common.DisasmFlags & ACPI_PARSEOP_COMPOUND)
    582         {
    583             return;
    584         }
    585 
    586         /* Emit extra close paren for assignment within an expression */
    587 
    588         if (Op->Common.DisasmFlags & ACPI_PARSEOP_ASSIGNMENT)
    589         {
    590             AcpiOsPrintf (")");
    591         }
    592         break;
    593 
    594     case AML_INDEX_OP:
    595 
    596         /* This is case for unsupported Index() source constants */
    597 
    598         if (Op->Common.DisasmFlags & ACPI_PARSEOP_CLOSING_PAREN)
    599         {
    600             AcpiOsPrintf (")");
    601         }
    602         return;
    603 
    604     /* No need for parens for these */
    605 
    606     case AML_DECREMENT_OP:
    607     case AML_INCREMENT_OP:
    608     case AML_LNOT_OP:
    609     case AML_BIT_NOT_OP:
    610     case AML_STORE_OP:
    611         return;
    612 
    613     default:
    614 
    615         /* Always emit paren for non-ASL+ operators */
    616         break;
    617     }
    618 
    619     AcpiOsPrintf (")");
    620 }
    621 
    622 
    623 /*******************************************************************************
    624  *
    625  * FUNCTION:    AcpiDmGetCompoundSymbol
    626  *
    627  * PARAMETERS:  AslOpcode
    628  *
    629  * RETURN:      String containing the compound assignment symbol
    630  *
    631  * DESCRIPTION: Detect opcodes that can be converted to compound assignment,
    632  *              return the appropriate operator string.
    633  *
    634  ******************************************************************************/
    635 
    636 static char *
    637 AcpiDmGetCompoundSymbol (
    638    UINT16                   AmlOpcode)
    639 {
    640     char                    *Symbol;
    641 
    642 
    643     switch (AmlOpcode)
    644     {
    645     case AML_ADD_OP:
    646         Symbol = " += ";
    647         break;
    648 
    649     case AML_SUBTRACT_OP:
    650         Symbol = " -= ";
    651         break;
    652 
    653     case AML_MULTIPLY_OP:
    654         Symbol = " *= ";
    655         break;
    656 
    657     case AML_DIVIDE_OP:
    658         Symbol = " /= ";
    659         break;
    660 
    661     case AML_MOD_OP:
    662         Symbol = " %= ";
    663         break;
    664 
    665     case AML_SHIFT_LEFT_OP:
    666         Symbol = " <<= ";
    667         break;
    668 
    669     case AML_SHIFT_RIGHT_OP:
    670         Symbol = " >>= ";
    671         break;
    672 
    673     case AML_BIT_AND_OP:
    674         Symbol = " &= ";
    675         break;
    676 
    677     case AML_BIT_OR_OP:
    678         Symbol = " |= ";
    679         break;
    680 
    681     case AML_BIT_XOR_OP:
    682         Symbol = " ^= ";
    683         break;
    684 
    685     default:
    686 
    687         /* No operator string for all other opcodes */
    688 
    689         return (NULL);
    690     }
    691 
    692     return (Symbol);
    693 }
    694 
    695 
    696 /*******************************************************************************
    697  *
    698  * FUNCTION:    AcpiDmPromoteTarget
    699  *
    700  * PARAMETERS:  Op                  - Operator parse object
    701  *              Target              - Target associate with the Op
    702  *
    703  * RETURN:      None
    704  *
    705  * DESCRIPTION: Transform the parse tree by moving the target up to the first
    706  *              child of the Op.
    707  *
    708  ******************************************************************************/
    709 
    710 static void
    711 AcpiDmPromoteTarget (
    712     ACPI_PARSE_OBJECT       *Op,
    713     ACPI_PARSE_OBJECT       *Target)
    714 {
    715     ACPI_PARSE_OBJECT       *Child;
    716 
    717 
    718     /* Link target directly to the Op as first child */
    719 
    720     Child = Op->Common.Value.Arg;
    721     Op->Common.Value.Arg = Target;
    722     Target->Common.Next = Child;
    723 
    724     /* Find the last peer, it is linked to the target. Unlink it. */
    725 
    726     while (Child->Common.Next != Target)
    727     {
    728         Child = Child->Common.Next;
    729     }
    730 
    731     Child->Common.Next = NULL;
    732 }
    733 
    734 
    735 /*******************************************************************************
    736  *
    737  * FUNCTION:    AcpiDmIsValidTarget
    738  *
    739  * PARAMETERS:  Target              - Target Op from the parse tree
    740  *
    741  * RETURN:      TRUE if the Target is real. FALSE if it is just a placeholder
    742  *              Op that was inserted by the parser.
    743  *
    744  * DESCRIPTION: Determine if a Target Op is a placeholder Op or a real Target.
    745  *              In other words, determine if the optional target is used or
    746  *              not. Note: If Target is NULL, something is seriously wrong,
    747  *              probably with the parse tree.
    748  *
    749  ******************************************************************************/
    750 
    751 static BOOLEAN
    752 AcpiDmIsValidTarget (
    753     ACPI_PARSE_OBJECT       *Target)
    754 {
    755 
    756     if (!Target)
    757     {
    758         return (FALSE);
    759     }
    760 
    761     if ((Target->Common.AmlOpcode == AML_INT_NAMEPATH_OP) &&
    762         (Target->Common.Value.Arg == NULL))
    763     {
    764         return (FALSE);
    765     }
    766 
    767     return (TRUE);
    768 }
    769 
    770 
    771 /*******************************************************************************
    772  *
    773  * FUNCTION:    AcpiDmIsTargetAnOperand
    774  *
    775  * PARAMETERS:  Target              - Target associated with the expression
    776  *              Operand             - An operand associated with expression
    777  *
    778  * RETURN:      TRUE if expression can be converted to a compound assignment.
    779  *              FALSE otherwise.
    780  *
    781  * DESCRIPTION: Determine if the Target duplicates the operand, in order to
    782  *              detect if the expression can be converted to a compound
    783  *              assigment. (+=, *=, etc.)
    784  *
    785  ******************************************************************************/
    786 
    787 static BOOLEAN
    788 AcpiDmIsTargetAnOperand (
    789     ACPI_PARSE_OBJECT       *Target,
    790     ACPI_PARSE_OBJECT       *Operand,
    791     BOOLEAN                 TopLevel)
    792 {
    793     const ACPI_OPCODE_INFO  *OpInfo;
    794     BOOLEAN                 Same;
    795 
    796 
    797     /*
    798      * Opcodes must match. Note: ignoring the difference between nameseg
    799      * and namepath for now. May be needed later.
    800      */
    801     if (Target->Common.AmlOpcode != Operand->Common.AmlOpcode)
    802     {
    803         return (FALSE);
    804     }
    805 
    806     /* Nodes should match, even if they are NULL */
    807 
    808     if (Target->Common.Node != Operand->Common.Node)
    809     {
    810         return (FALSE);
    811     }
    812 
    813     /* Determine if a child exists */
    814 
    815     OpInfo = AcpiPsGetOpcodeInfo (Operand->Common.AmlOpcode);
    816     if (OpInfo->Flags & AML_HAS_ARGS)
    817     {
    818         Same = AcpiDmIsTargetAnOperand (Target->Common.Value.Arg,
    819             Operand->Common.Value.Arg, FALSE);
    820         if (!Same)
    821         {
    822             return (FALSE);
    823         }
    824     }
    825 
    826     /* Check the next peer, as long as we are not at the top level */
    827 
    828     if ((!TopLevel) &&
    829          Target->Common.Next)
    830     {
    831         Same = AcpiDmIsTargetAnOperand (Target->Common.Next,
    832             Operand->Common.Next, FALSE);
    833         if (!Same)
    834         {
    835             return (FALSE);
    836         }
    837     }
    838 
    839     /* Supress the duplicate operand at the top-level */
    840 
    841     if (TopLevel)
    842     {
    843         Operand->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
    844     }
    845     return (TRUE);
    846 }
    847