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