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